Skip to content

Commit

Permalink
Support form
Browse files Browse the repository at this point in the history
  • Loading branch information
pontusab committed May 18, 2024
1 parent 8c21275 commit 41d1f01
Show file tree
Hide file tree
Showing 4 changed files with 284 additions and 1 deletion.
9 changes: 9 additions & 0 deletions apps/website/src/actions/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,12 @@ export const featureRequestSchema = z.object({
}),
category: z.string(),
});

export const sendSupportSchema = z.object({
email: z.string().email(),
fullName: z.string(),
subject: z.string(),
priority: z.string(),
type: z.string(),
message: z.string(),
});
61 changes: 61 additions & 0 deletions apps/website/src/actions/send-support-action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"use server";

import { PlainClient } from "@team-plain/typescript-sdk";
import { action } from "./safe-action";
import { sendSupportSchema } from "./schema";

const client = new PlainClient({
apiKey: process.env.PLAIN_API_KEY!,
});

const mapToPriorityNumber = (priority: string) => {
switch (priority) {
case "low":
return 0;
case "normal":
return 1;
case "high":
return 2;
case "urgent":
return 3;
default:
return 1;
}
};

export const sendSupportAction = action(sendSupportSchema, async (data) => {
const customer = await client.upsertCustomer({
identifier: {
emailAddress: data.email,
},
onCreate: {
fullName: data.fullName,
email: {
email: data.email,
isVerified: true,
},
},
onUpdate: {},
});

const response = await client.createThread({
title: data.subject,
description: data.message,
priority: mapToPriorityNumber(data.priority),
customerIdentifier: {
customerId: customer.data?.customer.id,
},
// Support
labelTypeIds: ["lt_01HV93FQT6NSC1EN2HHA6BG9WK"],
components: [
{
componentText: {
text: data.message,
},
},
],
});

console.log(response);
return response;
});
11 changes: 10 additions & 1 deletion apps/website/src/app/support/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import { SupportForm } from "@/components/support-form";
import type { Metadata } from "next";

export const metadata: Metadata = {
title: "Support",
};

export default function Page() {
return null;
return (
<div className="max-w-[750px] m-auto">
<h1 className="mt-24 font-medium text-center text-5xl mb-16 leading-snug">
Support
</h1>

<SupportForm />
</div>
);
}
204 changes: 204 additions & 0 deletions apps/website/src/components/support-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
"use client";

import { sendSupportSchema } from "@/actions/schema";
import { sendSupportAction } from "@/actions/send-support-action";
import { zodResolver } from "@hookform/resolvers/zod";
import { Button } from "@midday/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@midday/ui/form";
import { Input } from "@midday/ui/input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@midday/ui/select";
import { Textarea } from "@midday/ui/textarea";
import { useToast } from "@midday/ui/use-toast";
import { Loader2 } from "lucide-react";
import { useAction } from "next-safe-action/hooks";
import { useForm } from "react-hook-form";
import type { z } from "zod";

export function SupportForm() {
const { toast } = useToast();

const form = useForm<z.infer<typeof sendSupportSchema>>({
resolver: zodResolver(sendSupportSchema),
defaultValues: {
email: "",
fullName: "",
subject: "",
type: "",
priority: "",
message: "",
},
});

const sendSupport = useAction(sendSupportAction, {
onSuccess: () => {
toast({
duration: 2500,
title: "Support ticket sent.",
variant: "success",
});

form.reset();
},
onError: () => {
toast({
duration: 3500,
variant: "error",
title: "Something went wrong pleaase try again.",
});
},
});

return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(sendSupport.execute)}
className="space-y-8"
>
<div className="flex space-x-4">
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Email</FormLabel>
<FormControl>
<Input placeholder="Email" {...field} />

This comment has been minimized.

Copy link
@sahildave

sahildave May 19, 2024

Hey! Kudos to pushing the update so soon.

Quick suggestion: Good to have type=email in the input field here to have initial validation before Zod kicks in. :)

This comment has been minimized.

Copy link
@pontusab

pontusab May 19, 2024

Author Contributor

Thanks buddy! adding that!

</FormControl>
<FormMessage />
</FormItem>
)}
/>

<FormField
control={form.control}
name="fullName"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Full Name</FormLabel>
<FormControl>
<Input placeholder="John Doe" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>

<FormField
control={form.control}
name="subject"
render={({ field }) => (
<FormItem>
<FormLabel>Subject</FormLabel>
<FormControl>
<Input
placeholder="Summary of the problem you have"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>

<div className="flex space-x-4">
<FormField
control={form.control}
name="type"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Product</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select Product" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="Transactions">Transactions</SelectItem>
<SelectItem value="Vault">Vault</SelectItem>
<SelectItem value="Inbox">Inbox</SelectItem>
<SelectItem value="Invoicing">Invoicing</SelectItem>
<SelectItem value="Tracker">Tracker</SelectItem>
<SelectItem value="AI">AI</SelectItem>
<SelectItem value="General">General</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="priority"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Severity</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select severity" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="low">Low</SelectItem>
<SelectItem value="normal">Normal</SelectItem>
<SelectItem value="high">High</SelectItem>
<SelectItem value="urgent">Urgent</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
</div>

<FormField
control={form.control}
name="message"
render={({ field }) => (
<FormItem>
<FormLabel>Message</FormLabel>
<FormControl>
<Textarea
placeholder="Describe the issue you're facing, along with any relevant information. Please be as detailed and specific as possible."
className="resize-none min-h-[150px]"
{...field}
/>
</FormControl>

<FormMessage />
</FormItem>
)}
/>

<Button type="submit" disabled={sendSupport.status === "executing"}>
{sendSupport.status === "executing" ? (
<Loader2 className="h-4 w-4 animate-spin" />
) : (
"Submit"
)}
</Button>
</form>
</Form>
);
}

0 comments on commit 41d1f01

Please sign in to comment.