Skip to content

Commit

Permalink
feat: add email address to feedback form (#574)
Browse files Browse the repository at this point in the history
  • Loading branch information
abvthecity authored Mar 25, 2024
1 parent 0161d35 commit f494008
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 12 deletions.
1 change: 1 addition & 0 deletions packages/ui/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@headlessui/react": "^1.7.18",
"@radix-ui/colors": "^3.0.0",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-radio-group": "^1.1.3",
Expand Down
6 changes: 6 additions & 0 deletions packages/ui/app/src/analytics/posthog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ export function identifyUser(userId: string): void {
});
}

export function registerPosthogProperties(properties: Record<string, unknown>): void {
safeAccessPosthog(() => {
posthog.register(properties);
});
}

export function resetPosthog(): void {
safeAccessPosthog(() => {
posthog.reset();
Expand Down
19 changes: 19 additions & 0 deletions packages/ui/app/src/components/FernCheckbox.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.fern-checkbox-label {
@apply flex cursor-pointer;
}

.fern-checkbox-item {
@apply ring-default relative mt-0.5 inline-block size-4 ring-1 rounded-sm ring-inset;
}

.fern-checkbox-item:hover {
@apply bg-tag-primary;
}

.fern-checkbox-item:focus {
@apply outline outline-4 outline-offset-0 outline-tag-primary;
}

.fern-checkbox-indicator {
@apply size-4 bg-accent flex items-center justify-center text-accent-primary-contrast rounded-sm;
}
36 changes: 36 additions & 0 deletions packages/ui/app/src/components/FernCheckbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as Checkbox from "@radix-ui/react-checkbox";
import { CheckIcon } from "@radix-ui/react-icons";
import cn from "clsx";
import { FC, ReactNode } from "react";
import "./FernCheckbox.css";

interface FernCheckboxProps extends Checkbox.CheckboxProps {
labelClassName?: string;
label?: ReactNode;
helperText?: ReactNode;
compact?: boolean;
}

export const FernCheckbox: FC<FernCheckboxProps> = ({
labelClassName,
label,
helperText,
children,
className,
compact,
...props
}) => (
<label className={cn("fern-checkbox-label", { compact })}>
<Checkbox.Root className="fern-checkbox-item" {...props}>
<Checkbox.Indicator className="fern-checkbox-indicator">
<CheckIcon />
</Checkbox.Indicator>
</Checkbox.Root>

<div className="ml-2 flex-1">
<div className={cn("text-sm font-semibold", labelClassName)}>{label}</div>
{helperText && <p className="t-muted mb-0 text-xs">{helperText}</p>}
{children}
</div>
</label>
);
9 changes: 5 additions & 4 deletions packages/ui/app/src/components/FernRadioGroup.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
}

.fern-radio-item {
@apply ring-default relative mt-0.5 inline-block size-4 rounded-lg ring-1 ring-inset;
@apply ring-default relative mt-0.5 inline-block size-4 rounded-full ring-1 ring-inset;
}

.fern-radio-item:hover {
Expand All @@ -23,10 +23,11 @@
}

.fern-radio-indicator {
@apply size-4 bg-accent flex items-center justify-center rounded-lg;
@apply size-4 bg-accent flex items-center justify-center rounded-full;
}

.fern-radio-indicator:after {
@apply bg-background absolute size-2 rounded;
.fern-radio-indicator::after {
@apply bg-background absolute size-2 rounded-full;

content: "";
}
4 changes: 2 additions & 2 deletions packages/ui/app/src/components/FernRadioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ export const FernRadioGroup: FC<FernRadioGroupProps> = ({ options, className, co
<RadioGroup.Indicator className="fern-radio-indicator" />
</RadioGroup.Item>
<div className="ml-2 flex-1">
<div className={cn("text-sm", item.labelClassName)}>{item.label}</div>
{item.helperText && <p className="t-muted mb-0 text-xs">{item.helperText}</p>}
<div className={cn("text-sm font-semibold", item.labelClassName)}>{item.label}</div>
{item.helperText && <p className="t-muted mb-0 text-sm">{item.helperText}</p>}
{typeof item.children === "function"
? item.children(props.value === item.value)
: item.children}
Expand Down
19 changes: 16 additions & 3 deletions packages/ui/app/src/custom-docs-page/Feedback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import cn from "clsx";
import { useRouter } from "next/router";
import { FC, useCallback, useEffect, useRef, useState } from "react";
import { ThumbsDown, ThumbsUp } from "react-feather";
import { capturePosthogEvent } from "../analytics/posthog";
import { capturePosthogEvent, registerPosthogProperties } from "../analytics/posthog";
import { FernButton } from "../components/FernButton";
import { FeedbackForm } from "./FeedbackForm";
import { FeedbackFormDialog } from "./FeedbackFormDialog";
Expand Down Expand Up @@ -51,11 +51,24 @@ export const Feedback: FC<FeedbackProps> = ({ className }) => {
};

const handleSubmitFeedback = useCallback(
(feedbackId: string, message: string) => {
({
feedbackId,
feedbackMessage,
email,
showEmailInput,
}: {
feedbackId: string;
feedbackMessage: string;
email: string;
showEmailInput: boolean | "indeterminate";
}) => {
registerPosthogProperties({ email });
capturePosthogEvent("feedback_submitted", {
satisfied: feedback === "yes" ? true : false,
feedback: feedbackId,
message,
message: feedbackMessage,
email,
allowFollowUpViaEmail: showEmailInput === true,
});
setSent(true);
},
Expand Down
47 changes: 44 additions & 3 deletions packages/ui/app/src/custom-docs-page/FeedbackForm.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
import { useKeyboardPress } from "@fern-ui/react-commons";
import { useAtom } from "jotai";
import { atomWithStorage } from "jotai/utils";
import { FC, useCallback, useMemo, useRef, useState } from "react";
import { FernButton } from "../components/FernButton";
import { FernCheckbox } from "../components/FernCheckbox";
import { FernDropdown } from "../components/FernDropdown";
import { FernInput } from "../components/FernInput";
import { FernRadioGroup } from "../components/FernRadioGroup";
import { FernTextarea } from "../components/FernTextarea";

interface FeedbackFormProps {
feedback: "yes" | "no" | undefined;
onSubmit: (feedbackId: string, message: string) => void;
onSubmit: (feedback: {
feedbackId: string;
feedbackMessage: string;
email: string;
showEmailInput: boolean | "indeterminate";
}) => void;
}

const SHOW_EMAIL_INPUT_ATOM = atomWithStorage<boolean | "indeterminate">("feedback-show-email-input", false);
const EMAIL_ATOM = atomWithStorage<string>("feedback-email", "");

export const FeedbackForm: FC<FeedbackFormProps> = ({ feedback, onSubmit }) => {
const textareaRef = useRef<HTMLTextAreaElement>(null);
const [feedbackId, setFeedbackId] = useState<string>();
const [feedbackMessage, setFeedbackMessage] = useState<string>("");
const [showEmailInput, setShowEmailInput] = useAtom(SHOW_EMAIL_INPUT_ATOM);
const [email, setEmail] = useAtom(EMAIL_ATOM);

const legend = feedback === "yes" ? "What did you like?" : feedback === "no" ? "What went wrong?" : "Feedback";
const feedbackOptions = useMemo<FernDropdown.Option[]>(() => {
Expand All @@ -28,7 +42,7 @@ export const FeedbackForm: FC<FeedbackFormProps> = ({ feedback, onSubmit }) => {
active ? (
<FernTextarea
ref={textareaRef}
autoFocus={true}
// autoFocus={true}
className="mt-2 w-full"
placeholder="(Optional) Tell us more about your experience"
onValueChange={setFeedbackMessage}
Expand Down Expand Up @@ -74,7 +88,12 @@ export const FeedbackForm: FC<FeedbackFormProps> = ({ feedback, onSubmit }) => {
if (feedbackId == null) {
return;
}
onSubmit(feedbackId, feedbackMessage);
onSubmit({
feedbackId,
feedbackMessage,
email,
showEmailInput,
});
};

return (
Expand All @@ -87,6 +106,7 @@ export const FeedbackForm: FC<FeedbackFormProps> = ({ feedback, onSubmit }) => {
value={feedbackId}
onValueChange={setFeedbackId}
options={feedbackOptions}
autoFocus={true}
/>
) : (
<FernTextarea
Expand All @@ -98,6 +118,27 @@ export const FeedbackForm: FC<FeedbackFormProps> = ({ feedback, onSubmit }) => {
/>
)}

<hr className="border-border-concealed my-4" />

<div className="mt-4">
<FernCheckbox
label="Yes, it's okay to follow up by email."
checked={showEmailInput}
onCheckedChange={setShowEmailInput}
autoFocus={false}
>
{showEmailInput && (
<FernInput
className="mt-2"
type="email"
placeholder="[email protected]"
value={email}
onValueChange={setEmail}
/>
)}
</FernCheckbox>
</div>

<FernButton
full={true}
intent="primary"
Expand Down
31 changes: 31 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f494008

Please sign in to comment.