Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
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
6 changes: 6 additions & 0 deletions .server-changes/hipaa-addon-pricing-cta.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
area: webapp
type: feature
---

Request a HIPAA BAA add-on directly from any paid pricing tier in the dashboard.
32 changes: 24 additions & 8 deletions apps/webapp/app/components/Feedback.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { conform, useForm } from "@conform-to/react";
import { parse } from "@conform-to/zod";
import { InformationCircleIcon, ArrowUpCircleIcon } from "@heroicons/react/20/solid";
import { EnvelopeIcon } from "@heroicons/react/24/solid";
import { EnvelopeIcon, ShieldCheckIcon } from "@heroicons/react/24/solid";
import { Form, useActionData, useLocation, useNavigation, useSearchParams } from "@remix-run/react";
import { type ReactNode, useEffect, useState } from "react";
import { type FeedbackType, feedbackTypeLabel, schema } from "~/routes/resources.feedback";
import { type FeedbackType, feedbackTypes, schema } from "~/routes/resources.feedback";
import { Button } from "./primitives/Buttons";
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "./primitives/Dialog";
import { Fieldset } from "./primitives/Fieldset";
Expand Down Expand Up @@ -84,9 +84,12 @@ export function Feedback({ button, defaultValue = "bug", onOpenChange }: Feedbac
How can we help? We read every message and will respond as quickly as we can.
</Paragraph>
</div>
{!(type === "feature" || type === "help" || type === "concurrency") && (
<hr className="border-grid-dimmed" />
)}
{!(
type === "feature" ||
type === "help" ||
type === "concurrency" ||
type === "hipaa"
) && <hr className="border-grid-dimmed" />}
<Form method="post" action="/resources/feedback" {...form.props} className="w-full">
<Fieldset className="max-w-full gap-y-3">
<input value={location.pathname} {...conform.input(path, { type: "hidden" })} />
Expand Down Expand Up @@ -132,19 +135,32 @@ export function Feedback({ button, defaultValue = "bug", onOpenChange }: Feedbac
</Paragraph>
</InfoPanel>
)}
{type === "hipaa" && (
<InfoPanel
icon={ShieldCheckIcon}
iconClassName="text-green-500"
panelClassName="w-full mb-2"
>
<Paragraph variant="small">
We offer a signed Business Associate Agreement (BAA) as a paid add-on on any
paid plan. To help us get back to you quickly, please include your company
name, and a brief description of the PHI workload you plan to run.
</Paragraph>
</InfoPanel>
)}
<Select
{...conform.select(feedbackType)}
variant="tertiary/medium"
value={type}
defaultValue={type}
setValue={(v) => setType(v as FeedbackType)}
placeholder="Select type"
text={(value) => feedbackTypeLabel[value as FeedbackType]}
text={(value) => feedbackTypes[value as FeedbackType].label}
dropdownIcon
>
{Object.entries(feedbackTypeLabel).map(([name, title]) => (
{Object.entries(feedbackTypes).map(([name, { label }]) => (
<SelectItem key={name} value={name}>
{title}
{label}
</SelectItem>
))}
</Select>
Expand Down
65 changes: 51 additions & 14 deletions apps/webapp/app/routes/resources.feedback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,55 @@ import { sendToPlain } from "~/utils/plain.server";

let client: PlainClient | undefined;

export const feedbackTypeLabel = {
bug: "Bug report",
feature: "Feature request",
help: "Help me out",
enterprise: "Enterprise enquiry",
feedback: "General feedback",
concurrency: "Increase my concurrency",
region: "Suggest a new region",
};
export const feedbackTypes = {
bug: {
label: "Bug report",
labelTypeId: "lt_01HB920BTPFS36KH1JT9C36YVY",
threadTitle: "Contact form: Bug report",
},
feature: {
label: "Feature request",
labelTypeId: "lt_01HB920BV8CJGYXVE15WWN6P07",
threadTitle: "Contact form: Feature request",
},
help: {
label: "Help me out",
labelTypeId: "lt_01KTVCAPZY5ZJ0SS4ACMXWYYT3",
threadTitle: "Contact form: Help me out",
},
enterprise: {
label: "Enterprise enquiry",
labelTypeId: "lt_01K7PF5EV2877EH4SZYB667FW4",
threadTitle: "Contact form: Enterprise enquiry",
},
feedback: {
label: "General feedback",
labelTypeId: "lt_01HB920BSRZ3RA1ETHBVEB5ST2",
threadTitle: "Contact form: General feedback",
},
concurrency: {
label: "Increase my concurrency",
labelTypeId: "lt_01KTVCCY2PDE5V6WV2PQ8N85K2",
threadTitle: "Contact form: Increase my concurrency",
},
region: {
label: "Suggest a new region",
labelTypeId: "lt_01KTVCDPYYBW6KS9H5V8MTQ0GG",
threadTitle: "Contact form: Suggest a new region",
},
hipaa: {
label: "HIPAA BAA request",
labelTypeId: "lt_01KS54WBRYKE6DY369KPK2SS4W",
threadTitle: "Contact form: HIPAA BAA request",
},
} as const satisfies Record<
string,
{ label: string; labelTypeId?: string; threadTitle: string }
>;

export type FeedbackType = keyof typeof feedbackTypeLabel;
export type FeedbackType = keyof typeof feedbackTypes;

const feedbackTypeLiterals = Object.keys(feedbackTypeLabel).map((key) => z.literal(key));
const feedbackTypeLiterals = Object.keys(feedbackTypes).map((key) => z.literal(key));

const feedbackType = z.union(
[feedbackTypeLiterals[0], feedbackTypeLiterals[1], ...feedbackTypeLiterals.slice(2)],
Expand All @@ -46,16 +82,17 @@ export async function action({ request }: ActionFunctionArgs) {
return json(submission);
}

const title = feedbackTypeLabel[submission.value.feedbackType as FeedbackType];
const inquiry = feedbackTypes[submission.value.feedbackType as FeedbackType];
try {
await sendToPlain({
userId: user.id,
email: user.email,
name: user.name ?? user.displayName ?? user.email,
title,
title: inquiry.threadTitle,
Comment thread
D-K-P marked this conversation as resolved.
labelTypeIds: inquiry.labelTypeId ? [inquiry.labelTypeId] : undefined,
components: [
uiComponent.text({
text: `New ${title} reported by ${user.name} (${user.email})`,
text: `New ${inquiry.label} reported by ${user.name} (${user.email})`,
}),
uiComponent.divider({ spacingSize: "M" }),
uiComponent.text({
Expand Down
Loading
Loading