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

feat: send content feedback plausible events #12400

Merged
merged 13 commits into from
Jan 27, 2025
117 changes: 117 additions & 0 deletions src/components/docFeedback/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
'use client';
import {Fragment, useState} from 'react';
import * as Sentry from '@sentry/browser';

import {usePlausibleEvent} from 'sentry-docs/hooks/usePlausibleEvent';

import {Modal} from '../modal';

type Props = {
pathname: string;
};

export function DocFeedback({pathname}: Props) {
const {emit} = usePlausibleEvent();
const [showFeedbackModal, setShowFeedbackModal] = useState(false);
const [feedbackSubmitted, setFeedbackSubmitted] = useState(false);

const handleFeedback = (helpful: boolean) => {
a-hariti marked this conversation as resolved.
Show resolved Hide resolved
emit('Doc Feedback', {props: {page: pathname, helpful}});

if (!helpful) {
setShowFeedbackModal(true);
}
};

const handleSubmitFeedback = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const comments = formData.get('comments') as string;

try {
Sentry.captureFeedback(
{message: comments},
{captureContext: {tags: {page: pathname}}}
);
setFeedbackSubmitted(true);
} catch (error) {
// eslint-disable-next-line no-console
console.error('Failed to submit feedback:', error);
a-hariti marked this conversation as resolved.
Show resolved Hide resolved
}
};

return (
<Fragment>
<div className="flex items-center gap-2 py-4 border-t border-[var(--gray-6)]">
<span className="text-sm">Was this helpful?</span>
<button
onClick={() => handleFeedback(true)}
className="py-2 px-4 gap-4 hover:bg-[var(--gray-3)] rounded-full flex items-center justify-center"
aria-label="Yes, this was helpful"
>
Yes 👍
</button>
<button
onClick={() => handleFeedback(false)}
className="py-2 px-4 gap-4 hover:bg-[var(--gray-3)] rounded-full flex items-center justify-center"
aria-label="No, this wasn't helpful"
>
No 👎
</button>
</div>

<Modal
isOpen={showFeedbackModal}
onClose={() => {
setShowFeedbackModal(false);
setFeedbackSubmitted(false);
}}
title="Help us improve"
a-hariti marked this conversation as resolved.
Show resolved Hide resolved
>
{feedbackSubmitted ? (
<div className="text-center">
<h3 className="text-lg font-medium mb-2">Thank you for your feedback!</h3>
<p className="text-[var(--gray-11)] p-0 m-0">
We appreciate your help in making our documentation better.
</p>
</div>
) : (
<form onSubmit={handleSubmitFeedback} className="space-y-4">
<p className="text-[var(--gray-11)] p-0 m-0">
We'd love to hear more about how we can improve this page. Your feedback
helps us make our documentation better for everyone.
</p>
<div>
<label htmlFor="comments" className="block text-sm font-medium mb-4">
What could we improve?
</label>
<textarea
id="comments"
name="comments"
required
rows={4}
className="w-full px-3 py-2 border border-[var(--gray-6)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--accent)] bg-transparent"
placeholder="Please share your suggestions..."
/>
</div>
<div className="flex justify-end gap-3">
<button
type="button"
onClick={() => setShowFeedbackModal(false)}
className="px-4 py-2 text-sm hover:bg-[var(--gray-3)] rounded-lg"
>
Cancel
</button>
<button
type="submit"
className="px-4 py-2 text-sm bg-[var(--accent-purple)] rounded-lg"
>
Submit feedback
</button>
</div>
</form>
)}
</Modal>
</Fragment>
);
}
3 changes: 3 additions & 0 deletions src/components/docPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import './type.scss';
import {Banner} from '../banner';
import {Breadcrumbs} from '../breadcrumbs';
import {CodeContextProvider} from '../codeContext';
import {DocFeedback} from '../docFeedback';
import {GitHubCTA} from '../githubCTA';
import {Header} from '../header';
import Mermaid from '../mermaid';
Expand Down Expand Up @@ -91,6 +92,8 @@ export function DocPage({
<CodeContextProvider>{children}</CodeContextProvider>
</div>

<DocFeedback pathname={pathname} />

<div className="grid grid-cols-2 gap-4 not-prose mt-16">
<div className="col-span-1">
{previousPage && <PaginationNav node={previousPage} title="Previous" />}
Expand Down
100 changes: 100 additions & 0 deletions src/components/modal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
'use client';
import {useEffect, useRef} from 'react';

type Props = {
children: React.ReactNode;
isOpen: boolean;
onClose: () => void;
title: string;
};

export function Modal({isOpen, onClose, children, title}: Props) {
const modalRef = useRef<HTMLDialogElement>(null);

useEffect(() => {
if (isOpen) {
modalRef.current?.showModal();
document.body.style.overflow = 'hidden';
} else {
modalRef.current?.close();
document.body.style.overflow = 'unset';
}
}, [isOpen]);

const handleClose = () => {
onClose();
};

const handleBackdropClick = (e: React.MouseEvent<HTMLDialogElement>) => {
if (e.target === modalRef.current) {
handleClose();
}
};

if (!isOpen) {
return null;
}

return (
<dialog
ref={modalRef}
className="backdrop:bg-[var(--gray-12)]/50 backdrop:backdrop-blur-sm p-0 bg-transparent w-full max-w-lg m-auto data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-top-[2%] data-[state=open]:slide-in-from-top-[2%] duration-200"
onClick={handleBackdropClick}
>
<div className="bg-[var(--gray-1)] rounded-lg shadow-lg border border-[var(--gray-6)] motion-safe:animate-modal-enter px-4">
<div className="flex items-center justify-between py-5 border-b border-[var(--gray-6)] px-4">
<h2 className="text-lg font-medium p!-0 !m-0">{title}</h2>
<button
onClick={handleClose}
className="p-2 hover:bg-[var(--gray-3)] rounded-full transition-colors"
aria-label="Close modal"
>
<svg width="12" height="12" viewBox="0 0 12 12">
<path
d="M6 4.586l4.293-4.293 1.414 1.414L7.414 6l4.293 4.293-1.414 1.414L6 7.414l-4.293 4.293-1.414-1.414L4.586 6 .293 1.707 1.707.293 6 4.586z"
fill="currentColor"
/>
</svg>
</button>
</div>
<div className="p-4">{children}</div>
</div>

<style>{`
@keyframes modal-enter {
from {
opacity: 0;
transform: translate3d(0, -1rem, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}

.animate-modal-enter {
animation: modal-enter 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

::backdrop {
-webkit-backdrop-filter: blur(4px);
backdrop-filter: blur(4px);
background: rgba(var(--gray-12-rgb), 0.5);
transition: all 0.2s ease-in-out;
}

dialog[open]::backdrop {
opacity: 1;
}

dialog:not([open])::backdrop {
opacity: 0;
}

dialog::backdrop {
opacity: 0;
}
`}</style>
</dialog>
);
}
4 changes: 4 additions & 0 deletions src/hooks/usePlausibleEvent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import {ReadProgressMilestone} from 'sentry-docs/types/plausible';

// Adding custom events here will make them available via the hook
type PlausibleEventProps = {
['Doc Feedback']: {
helpful: boolean;
page: string;
};
['Read Progress']: {
page: string;
readProgress: ReadProgressMilestone;
Expand Down
Loading