Skip to content

Commit 0d06531

Browse files
authored
docs: add feedback widget (#394)
## 📝 Description Implements a feedback widget to upvote/downvote individual pages. Works with any docs in any version. Data is saved in a Google Forms backend, which we can dump in a Google Sheet to analyze Fixes #233 ## ✅ Checklist - [X] I have tested this change - [ ] This change requires documentation update
1 parent 8e7fd4e commit 0d06531

File tree

4 files changed

+184
-0
lines changed

4 files changed

+184
-0
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* This component implements a feedback widget to upvote and downvote individual pages
3+
* data is saved on a Google Forms, the IDs for the form and fields are hardcoded in the giveFeedback function
4+
*/
5+
6+
import React, {useState} from 'react';
7+
import useIsBrowser from '@docusaurus/useIsBrowser';
8+
9+
const DocsRating = ({label}) => {
10+
const isBrowser = useIsBrowser();
11+
if (!isBrowser) {
12+
return null;
13+
}
14+
15+
const [haveVoted, setHaveVoted] = useState(false);
16+
17+
const giveFeedback = (value) => {
18+
if (typeof window !== 'undefined') {
19+
20+
// Google Form and fields IDs
21+
const form_id = '1FAIpQLSe0o2pDg8bQB245_Rl1OpDHrPXasUV5_USOC4fSKWaFywRKuw'
22+
const field_id_url = 'entry.412997010';
23+
const field_id_upvote = 'entry.1841322984';
24+
const url = window.location.pathname;
25+
26+
const formData = new FormData();
27+
// formData.append(field_id_url, label);
28+
formData.append(field_id_url, url);
29+
formData.append(field_id_upvote, value);
30+
31+
fetch('https://docs.google.com/forms/d/e/' + form_id + '/formResponse', {
32+
method: 'POST',
33+
mode: 'no-cors',
34+
body: formData
35+
}).then(response => {
36+
setHaveVoted(true);
37+
console.log('Success:', response.status);
38+
});
39+
};
40+
};
41+
42+
43+
return (
44+
<div className="docsRating">
45+
{haveVoted ? (
46+
'Thanks for letting us know!'
47+
) : (
48+
<>
49+
Is this page useful?
50+
<svg
51+
className="i_thumbsup"
52+
aria-label="Like"
53+
onClick={() => giveFeedback(1)}
54+
xmlns="http://www.w3.org/2000/svg"
55+
viewBox="0 0 81.13 89.76">
56+
<path d="M22.9 6a18.57 18.57 0 002.67 8.4 25.72 25.72 0 008.65 7.66c3.86 2 8.67 7.13 13.51 11 3.86 3.11 8.57 7.11 11.54 8.45s13.59.26 14.64 1.17c1.88 1.63 1.55 9-.11 15.25-1.61 5.86-5.96 10.55-6.48 16.86-.4 4.83-2.7 4.88-10.93 4.88h-1.35c-3.82 0-8.24 2.93-12.92 3.62a68 68 0 01-9.73.5c-3.57 0-7.86-.08-13.25-.08-3.56 0-4.71-1.83-4.71-4.48h8.42a3.51 3.51 0 000-7H12.28a2.89 2.89 0 01-2.88-2.88 1.91 1.91 0 01.77-1.78h16.46a3.51 3.51 0 000-7H12.29c-3.21 0-4.84-1.83-4.84-4a6.41 6.41 0 011.17-3.78h19.06a3.5 3.5 0 100-7H9.75A3.51 3.51 0 016 42.27a3.45 3.45 0 013.75-3.48h13.11c5.61 0 7.71-3 5.71-5.52-4.43-4.74-10.84-12.62-11-18.71-.15-6.51 2.6-7.83 5.36-8.56m0-6a6.18 6.18 0 00-1.53.2c-6.69 1.77-10 6.65-9.82 14.5.08 5.09 2.99 11.18 8.52 18.09H9.74a9.52 9.52 0 00-6.23 16.9 12.52 12.52 0 00-2.07 6.84 9.64 9.64 0 003.65 7.7 7.85 7.85 0 00-1.7 5.13 8.9 8.9 0 005.3 8.13 6 6 0 00-.26 1.76c0 6.37 4.2 10.48 10.71 10.48h13.25a73.75 73.75 0 0010.6-.56 35.89 35.89 0 007.58-2.18 17.83 17.83 0 014.48-1.34h1.35c4.69 0 7.79 0 10.5-1 3.85-1.44 6-4.59 6.41-9.38.2-2.46 1.42-4.85 2.84-7.62a41.3 41.3 0 003.42-8.13 48 48 0 001.59-10.79c.1-5.13-1-8.48-3.35-10.55-2.16-1.87-4.64-1.87-9.6-1.88a46.86 46.86 0 01-6.64-.29c-1.92-.94-5.72-4-8.51-6.3l-1.58-1.28c-1.6-1.3-3.27-2.79-4.87-4.23-3.33-3-6.47-5.79-9.61-7.45a20.2 20.2 0 01-6.43-5.53 12.44 12.44 0 01-1.72-5.36 6 6 0 00-6-5.86z" />
57+
</svg>
58+
<svg
59+
className="i_thumbsdown"
60+
aria-label="Dislike"
61+
onClick={() => giveFeedback(0)}
62+
xmlns="http://www.w3.org/2000/svg"
63+
viewBox="0 0 81.13 89.76">
64+
<path d="M22.9 6a18.57 18.57 0 002.67 8.4 25.72 25.72 0 008.65 7.66c3.86 2 8.67 7.13 13.51 11 3.86 3.11 8.57 7.11 11.54 8.45s13.59.26 14.64 1.17c1.88 1.63 1.55 9-.11 15.25-1.61 5.86-5.96 10.55-6.48 16.86-.4 4.83-2.7 4.88-10.93 4.88h-1.35c-3.82 0-8.24 2.93-12.92 3.62a68 68 0 01-9.73.5c-3.57 0-7.86-.08-13.25-.08-3.56 0-4.71-1.83-4.71-4.48h8.42a3.51 3.51 0 000-7H12.28a2.89 2.89 0 01-2.88-2.88 1.91 1.91 0 01.77-1.78h16.46a3.51 3.51 0 000-7H12.29c-3.21 0-4.84-1.83-4.84-4a6.41 6.41 0 011.17-3.78h19.06a3.5 3.5 0 100-7H9.75A3.51 3.51 0 016 42.27a3.45 3.45 0 013.75-3.48h13.11c5.61 0 7.71-3 5.71-5.52-4.43-4.74-10.84-12.62-11-18.71-.15-6.51 2.6-7.83 5.36-8.56m0-6a6.18 6.18 0 00-1.53.2c-6.69 1.77-10 6.65-9.82 14.5.08 5.09 2.99 11.18 8.52 18.09H9.74a9.52 9.52 0 00-6.23 16.9 12.52 12.52 0 00-2.07 6.84 9.64 9.64 0 003.65 7.7 7.85 7.85 0 00-1.7 5.13 8.9 8.9 0 005.3 8.13 6 6 0 00-.26 1.76c0 6.37 4.2 10.48 10.71 10.48h13.25a73.75 73.75 0 0010.6-.56 35.89 35.89 0 007.58-2.18 17.83 17.83 0 014.48-1.34h1.35c4.69 0 7.79 0 10.5-1 3.85-1.44 6-4.59 6.41-9.38.2-2.46 1.42-4.85 2.84-7.62a41.3 41.3 0 003.42-8.13 48 48 0 001.59-10.79c.1-5.13-1-8.48-3.35-10.55-2.16-1.87-4.64-1.87-9.6-1.88a46.86 46.86 0 01-6.64-.29c-1.92-.94-5.72-4-8.51-6.3l-1.58-1.28c-1.6-1.3-3.27-2.79-4.87-4.23-3.33-3-6.47-5.79-9.61-7.45a20.2 20.2 0 01-6.43-5.53 12.44 12.44 0 01-1.72-5.36 6 6 0 00-6-5.86z" />
65+
</svg>
66+
</>
67+
)}
68+
</div>
69+
);
70+
};
71+
72+
export default DocsRating;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
.lastUpdated {
9+
margin-top: 0.2rem;
10+
font-style: italic;
11+
font-size: smaller;
12+
}
13+
14+
.editButtons {
15+
column-gap: 0.4rem;
16+
display: flex;
17+
flex: 1;
18+
}
19+
20+
@media (min-width: 997px) {
21+
.lastUpdated {
22+
text-align: end;
23+
}
24+
}
25+
26+

docs/src/css/custom.css

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,41 @@ iconify-icon {
140140
border-color: var(--ifm-color-gray-100) transparent transparent transparent;
141141
}
142142
}
143+
144+
.docsRating {
145+
display: inline-block;
146+
padding: 16px 30px 16px 40px;
147+
min-height: 66px;
148+
margin-top: 42px;
149+
margin-left: -32px;
150+
background-color: rgba(100, 215, 255, 0.3);
151+
text-align: center;
152+
color: #057594;
153+
line-height: 32px;
154+
font-weight: 500;
155+
border-radius: 0 var(--ifm-global-radius) var(--ifm-global-radius) 0;
156+
157+
svg {
158+
height: 1.5em;
159+
width: 1.5em;
160+
margin: 0 0 0 6px;
161+
162+
&:hover,
163+
&:focus {
164+
cursor: pointer;
165+
fill: var(--ifm-color-primary);
166+
}
167+
}
168+
169+
.i_thumbsup {
170+
fill: #56a211;
171+
transform: translateY(0.25em);
172+
margin-left: 12px;
173+
}
174+
175+
.i_thumbsdown {
176+
fill: #e9430f;
177+
transform: scale(-1, -1) translateY(-0.25em);
178+
}
179+
}
180+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import clsx from 'clsx';
3+
import {ThemeClassNames} from '@docusaurus/theme-common';
4+
import {useDoc} from '@docusaurus/plugin-content-docs/client';
5+
import TagsListInline from '@theme/TagsListInline';
6+
import EditMetaRow from '@theme/EditMetaRow';
7+
import DocsRating from '@site/src/components/DocsRating';
8+
9+
export default function DocItemFooter() {
10+
const {metadata} = useDoc();
11+
const {editUrl, lastUpdatedAt, lastUpdatedBy, tags} = metadata;
12+
const canDisplayTagsRow = tags.length > 0;
13+
const canDisplayEditMetaRow = !!(editUrl || lastUpdatedAt || lastUpdatedBy);
14+
const canDisplayFooter = canDisplayTagsRow || canDisplayEditMetaRow;
15+
if (!canDisplayFooter) {
16+
return null;
17+
}
18+
return (
19+
<>
20+
<DocsRating label={metadata.id} />
21+
<footer
22+
className={clsx(ThemeClassNames.docs.docFooter, 'docusaurus-mt-lg')}>
23+
{canDisplayTagsRow && (
24+
<div
25+
className={clsx(
26+
'row margin-top--sm',
27+
ThemeClassNames.docs.docFooterTagsRow,
28+
)}>
29+
<div className="col">
30+
<TagsListInline tags={tags} />
31+
</div>
32+
</div>
33+
)}
34+
{canDisplayEditMetaRow && (
35+
<EditMetaRow
36+
className={clsx(
37+
'margin-top--sm',
38+
ThemeClassNames.docs.docFooterEditMetaRow,
39+
)}
40+
editUrl={editUrl}
41+
lastUpdatedAt={lastUpdatedAt}
42+
lastUpdatedBy={lastUpdatedBy}
43+
/>
44+
)}
45+
</footer>
46+
</>
47+
);
48+
}

0 commit comments

Comments
 (0)