feat: add templates for transactional emails (#103)

* add template migration & router

* template CRUD

* templated transactional emails API

* zod schema fix & rearranging template columns
This commit is contained in:
Ganapathy S
2025-03-07 00:50:25 +05:30
committed by KM Koushik
parent 1c2417df2f
commit 38314a35dc
16 changed files with 981 additions and 8 deletions

View File

@@ -0,0 +1,113 @@
"use client";
import {
Table,
TableHeader,
TableRow,
TableHead,
TableBody,
TableCell,
} from "@unsend/ui/src/table";
import { api } from "~/trpc/react";
import { useUrlState } from "~/hooks/useUrlState";
import { Button } from "@unsend/ui/src/button";
import Spinner from "@unsend/ui/src/spinner";
import { formatDistanceToNow } from "date-fns";
// import DeleteCampaign from "./delete-campaign";
import Link from "next/link";
// import DuplicateCampaign from "./duplicate-campaign";
import { TextWithCopyButton } from "@unsend/ui/src/text-with-copy";
import DeleteTemplate from "./delete-template";
import DuplicateTemplate from "./duplicate-template";
export default function TemplateList() {
const [page, setPage] = useUrlState("page", "1");
const pageNumber = Number(page);
const templateQuery = api.template.getTemplates.useQuery({
page: pageNumber,
});
return (
<div className="mt-10 flex flex-col gap-4">
<div className="flex flex-col rounded-xl border border-border shadow">
<Table className="">
<TableHeader className="">
<TableRow className=" bg-muted/30">
<TableHead className="rounded-tl-xl">Name</TableHead>
<TableHead className="">ID</TableHead>
<TableHead className="">Created At</TableHead>
<TableHead className="rounded-tr-xl">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{templateQuery.isLoading ? (
<TableRow className="h-32">
<TableCell colSpan={4} className="text-center py-4">
<Spinner
className="w-6 h-6 mx-auto"
innerSvgClass="stroke-primary"
/>
</TableCell>
</TableRow>
) : templateQuery.data?.templates.length ? (
templateQuery.data?.templates.map((template) => (
<TableRow key={template.id} className="">
<TableCell className="font-medium">
<Link
className="underline underline-offset-4 decoration-dashed text-foreground hover:text-primary"
href={`/templates/${template.id}`}
>
{template.name}
</Link>
</TableCell>
<TableCell>
<TextWithCopyButton
value={template.id}
className="w-[200px] overflow-hidden"
/>
</TableCell>
<TableCell className="">
{formatDistanceToNow(new Date(template.createdAt), {
addSuffix: true,
})}
</TableCell>
<TableCell>
<div className="flex gap-2">
<DuplicateTemplate template={template} />
<DeleteTemplate template={template} />
</div>
</TableCell>
</TableRow>
))
) : (
<TableRow className="h-32">
<TableCell colSpan={4} className="text-center py-4">
No templates found
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
<div className="flex gap-4 justify-end">
<Button
size="sm"
onClick={() => setPage((pageNumber - 1).toString())}
disabled={pageNumber === 1}
>
Previous
</Button>
<Button
size="sm"
onClick={() => setPage((pageNumber + 1).toString())}
disabled={pageNumber >= (templateQuery.data?.totalPage ?? 0)}
>
Next
</Button>
</div>
</div>
);
}