Improved the feedback form
This commit is contained in:
@@ -8,7 +8,7 @@ import {
|
||||
useNavigation,
|
||||
} from "@remix-run/react";
|
||||
import { useState } from "react";
|
||||
import { schema } from "~/routes/resources.feedback";
|
||||
import { feedbackTypeLabel, schema } from "~/routes/resources.feedback";
|
||||
import { Button } from "./primitives/Buttons";
|
||||
import { Fieldset } from "./primitives/Fieldset";
|
||||
import { FormButtons } from "./primitives/FormButtons";
|
||||
@@ -67,7 +67,7 @@ export function Feedback() {
|
||||
Send us feedback
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent>
|
||||
<SheetContent size="sm">
|
||||
<SheetHeader className="justify-between">Give us feedback</SheetHeader>
|
||||
<SheetBody>
|
||||
<Paragraph variant="small" className="mb-4">
|
||||
@@ -82,14 +82,16 @@ export function Feedback() {
|
||||
<InputGroup>
|
||||
<Label>What kind of feedback do you have?</Label>
|
||||
<SelectGroup>
|
||||
<Select {...conform.input(feedbackType)} defaultValue="bug">
|
||||
<Select {...conform.input(feedbackType)} defaultValue={"bug"}>
|
||||
<SelectTrigger size="medium" width="full">
|
||||
<SelectValue placeholder="Type" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="bug">Bug report</SelectItem>
|
||||
<SelectItem value="feature">Feature request</SelectItem>
|
||||
<SelectItem value="help">Help me out</SelectItem>
|
||||
{Object.entries(feedbackTypeLabel).map(([key, value]) => (
|
||||
<SelectItem key={key} value={key}>
|
||||
{value}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</SelectGroup>
|
||||
@@ -104,6 +106,7 @@ export function Feedback() {
|
||||
</InputGroup>
|
||||
<FormError>{form.error}</FormError>
|
||||
<FormButtons
|
||||
className="max-w-md"
|
||||
confirmButton={
|
||||
<Button type="submit" variant="primary/medium">
|
||||
Send
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import { cn } from "~/utils/cn";
|
||||
|
||||
export function FormButtons({
|
||||
cancelButton,
|
||||
confirmButton,
|
||||
className,
|
||||
}: {
|
||||
cancelButton?: React.ReactNode;
|
||||
confirmButton: React.ReactNode;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<div className={cn("flex w-full items-center justify-between", className)}>
|
||||
{cancelButton ? cancelButton : <div />} {confirmButton}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import { parse } from "@conform-to/zod";
|
||||
import { ActionArgs, json } from "@remix-run/server-runtime";
|
||||
import { PlainClient } from "@team-plain/typescript-sdk";
|
||||
import {
|
||||
ComponentDividerSpacingSize,
|
||||
ComponentSpacerSize,
|
||||
ComponentTextColor,
|
||||
ComponentTextSize,
|
||||
PlainClient,
|
||||
} from "@team-plain/typescript-sdk";
|
||||
import { inspect } from "util";
|
||||
import { s } from "vitest/dist/index-6e18a03a";
|
||||
import { z } from "zod";
|
||||
import { env } from "~/env.server";
|
||||
import { redirectWithSuccessMessage } from "~/models/message.server";
|
||||
@@ -10,20 +15,31 @@ import { requireUser } from "~/services/session.server";
|
||||
|
||||
let client: PlainClient | undefined;
|
||||
|
||||
export const feedbackTypeLabel = {
|
||||
bug: "Bug report",
|
||||
feature: "Feature request",
|
||||
help: "Help me out",
|
||||
integration: "Request an integration",
|
||||
};
|
||||
|
||||
type FeedbackType = keyof typeof feedbackTypeLabel;
|
||||
|
||||
const feedbackTypeLiterals = Object.keys(feedbackTypeLabel).map((key) =>
|
||||
z.literal(key)
|
||||
);
|
||||
|
||||
const feedbackType = z.union(
|
||||
[z.literal("bug"), z.literal("feature"), z.literal("help")],
|
||||
[
|
||||
feedbackTypeLiterals[0],
|
||||
feedbackTypeLiterals[1],
|
||||
...feedbackTypeLiterals.slice(2),
|
||||
],
|
||||
{
|
||||
required_error: "Must be either 'bug' or 'feature'",
|
||||
invalid_type_error: "Must be either 'bug' or 'feature'",
|
||||
}
|
||||
);
|
||||
|
||||
const feedbackTypeLabel = {
|
||||
bug: "Bug",
|
||||
feature: "Feature request",
|
||||
help: "Help",
|
||||
};
|
||||
|
||||
export const schema = z.object({
|
||||
path: z.string(),
|
||||
feedbackType,
|
||||
@@ -77,10 +93,46 @@ export async function action({ request }: ActionArgs) {
|
||||
return json(submission);
|
||||
}
|
||||
|
||||
const title =
|
||||
feedbackTypeLabel[submission.value.feedbackType as FeedbackType];
|
||||
const upsertTimelineEntryRes = await client.upsertCustomTimelineEntry({
|
||||
customerId: upsertCustomerRes.data.customer.id,
|
||||
title: feedbackTypeLabel[submission.value.feedbackType],
|
||||
title,
|
||||
components: [
|
||||
{
|
||||
componentText: {
|
||||
text: `New ${title} reported by ${user.name} (${user.email})`,
|
||||
},
|
||||
},
|
||||
{
|
||||
componentDivider: {
|
||||
dividerSpacingSize: ComponentDividerSpacingSize.M,
|
||||
},
|
||||
},
|
||||
{
|
||||
componentText: {
|
||||
textSize: ComponentTextSize.S,
|
||||
textColor: ComponentTextColor.Muted,
|
||||
text: "Page",
|
||||
},
|
||||
},
|
||||
{
|
||||
componentText: {
|
||||
text: submission.value.path,
|
||||
},
|
||||
},
|
||||
{
|
||||
componentSpacer: {
|
||||
spacerSize: ComponentSpacerSize.M,
|
||||
},
|
||||
},
|
||||
{
|
||||
componentText: {
|
||||
textSize: ComponentTextSize.S,
|
||||
textColor: ComponentTextColor.Muted,
|
||||
text: "Message",
|
||||
},
|
||||
},
|
||||
{
|
||||
componentText: {
|
||||
text: submission.value.message,
|
||||
@@ -105,7 +157,7 @@ export async function action({ request }: ActionArgs) {
|
||||
return redirectWithSuccessMessage(
|
||||
submission.value.path,
|
||||
request,
|
||||
"Feedback submitted"
|
||||
"Thanks for your feedback! We'll get back to you soon."
|
||||
);
|
||||
} catch (e) {
|
||||
return json(e, { status: 400 });
|
||||
|
||||
Reference in New Issue
Block a user