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:
113
apps/web/src/app/(dashboard)/templates/template-list.tsx
Normal file
113
apps/web/src/app/(dashboard)/templates/template-list.tsx
Normal 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>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user