diff --git a/docs/src/components/FeedbackForm/index.js b/docs/src/components/FeedbackForm/index.js index d65098e951..cbde902ebf 100644 --- a/docs/src/components/FeedbackForm/index.js +++ b/docs/src/components/FeedbackForm/index.js @@ -1,35 +1,73 @@ import React, { useEffect, useState, useRef } from "react"; +import { Icon } from "@iconify/react"; import BrowserOnly from "@docusaurus/BrowserOnly"; -import { Icon } from "@iconify/react"; import Admonition from "@theme/Admonition"; import styles from "./styles.module.css"; +/** + * A feedback form component that is automatically added to the end of documentation pages. + * It can also be manually included in other pages by setting enablePopup to true. + * The form allows users to provide positive or negative feedback with optional comments + * and email for follow-up. Feedback is submitted to Netlify Forms via AJAX. + * + * Note: When adding new fields to this form, remember to update the static/netlify-forms.html + * file so that Netlify knows which fields to permit. If this is not updated, new fields + * in the form will be dropped. + */ export default function FeedbackForm({ enablePopup = false }) { + // this is used to ensure the response is categorized in netlify forms and that + // local state is remembered. const formName = "page-feedback"; + const [feedbackType, setFeedbackType] = useState(""); const [comment, setComment] = useState(""); const [url, setUrl] = useState(""); const [path, setPath] = useState(""); const [message, setMessage] = useState(""); + const [showFloatingPopup, setShowFloatingPopup] = useState(false); const [hasScrolled, setHasScrolled] = useState(false); + const [popupEnabled, setPopupEnabled] = useState(enablePopup); const feedbackFormRef = useRef(null); + // The popup will never show before the user has been on the page for 10s + const feedbackPopupTimeoutMs = 10000; + useEffect(() => { if (typeof window !== "undefined") { - if (window.location.hostname === "localhost") { - // setMessage("Feedback form disabled on localhost."); - // return; - } setUrl(window.location); setPath(window.location.pathname); } }, []); + // This effect sets up an intersection observer to detect when the feedback form + // comes into view. When the form is visible, it permanently disables the popup + // to prevent it from showing again. This ensures users who have found the form + // don't get interrupted by the popup. useEffect(() => { - if (enablePopup) { + if (feedbackFormRef.current) { + const observer = new IntersectionObserver( + (entries) => { + if (entries[0].isIntersecting) { + setShowFloatingPopup(false); + setPopupEnabled(false); + } + }, + { threshold: 0.1 } + ); + + observer.observe(feedbackFormRef.current); + + return () => { + observer.disconnect(); + }; + } + }, [feedbackFormRef.current]); + + useEffect(() => { + if (popupEnabled) { const handleScroll = () => { if (window.scrollY > 100) { setHasScrolled(true); @@ -43,19 +81,21 @@ export default function FeedbackForm({ enablePopup = false }) { if (hasScrolled) { setShowFloatingPopup(true); } - }, 10000); + }, feedbackPopupTimeoutMs); return () => { clearTimeout(timer); window.removeEventListener("scroll", handleScroll); }; } - }, [enablePopup, hasScrolled]); + }, [popupEnabled, hasScrolled]); + // feedback is stored in local storage to prevent the form / popup from showing again useEffect(() => { const feedbackSubmitted = localStorage.getItem(`${formName}-${path}`); if (feedbackSubmitted) { setMessage("Thank you for your feedback!"); + setPopupEnabled(false); } }, [path]); @@ -91,151 +131,171 @@ export default function FeedbackForm({ enablePopup = false }) { } }; - const FloatingPopup = () => ( -
How's this page?
-{message}
+ +
+ Got more to say? Questions for the OPA experts? Please come and find us on the{" "}
+
+ OPA Slack.
+ {" "}
+ The #help channel is a great place to get stated.
+
{message}
- -
- Got more to say? Questions for the OPA experts? Please come and find us on the{" "}
-
- OPA Slack.
- {" "}
- The #help channel is a great place to get stated.
-
We are always trying to make our documentation the best it can be and welcome your comments.
+ - ); - }} - - ); - } - - // NOTE: remember to update the static/netlify-forms.html file so that they - // know which files to permit. If this is not updated, new fields in the - // form will be dropped. - return ( -We are always trying to make our documentation the best it can be and welcome your comments.
- - -How's this page?
+