Update Biome formatting settings, improved self-hosting capability and reformatted all files
This commit is contained in:
@@ -7,14 +7,7 @@ import { useRouter } from "next/router";
|
||||
import React, { useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
Card,
|
||||
Dropdown,
|
||||
Editor,
|
||||
FullscreenLoader,
|
||||
Input,
|
||||
Tooltip,
|
||||
} from "../../components";
|
||||
import { Card, Dropdown, Editor, FullscreenLoader, Input, Tooltip } from "../../components";
|
||||
import { Dashboard } from "../../layouts";
|
||||
import { useActiveProject } from "../../lib/hooks/projects";
|
||||
import { useTemplate, useTemplates } from "../../lib/hooks/templates";
|
||||
@@ -63,25 +56,16 @@ export default function Index() {
|
||||
reset(template);
|
||||
}, [reset, template]);
|
||||
|
||||
if (
|
||||
!project ||
|
||||
!template ||
|
||||
(watch("body") as string | undefined) === undefined
|
||||
) {
|
||||
if (!project || !template || (watch("body") as string | undefined) === undefined) {
|
||||
return <FullscreenLoader />;
|
||||
}
|
||||
|
||||
const update = (data: TemplateValues) => {
|
||||
toast.promise(
|
||||
network.mock<Template, typeof TemplateSchemas.update>(
|
||||
project.secret,
|
||||
"PUT",
|
||||
"/v1/templates",
|
||||
{
|
||||
id: template.id,
|
||||
...data,
|
||||
},
|
||||
),
|
||||
network.mock<Template, typeof TemplateSchemas.update>(project.secret, "PUT", "/v1/templates", {
|
||||
id: template.id,
|
||||
...data,
|
||||
}),
|
||||
{
|
||||
loading: "Saving your template",
|
||||
success: () => {
|
||||
@@ -97,14 +81,9 @@ export default function Index() {
|
||||
const duplicate = async (e: { preventDefault: () => void }) => {
|
||||
e.preventDefault();
|
||||
toast.promise(
|
||||
network.mock<Template, typeof UtilitySchemas.id>(
|
||||
project.secret,
|
||||
"POST",
|
||||
"/v1/templates/duplicate",
|
||||
{
|
||||
id: template.id,
|
||||
},
|
||||
),
|
||||
network.mock<Template, typeof UtilitySchemas.id>(project.secret, "POST", "/v1/templates/duplicate", {
|
||||
id: template.id,
|
||||
}),
|
||||
{
|
||||
loading: "Duplicating your template",
|
||||
success: () => {
|
||||
@@ -122,20 +101,13 @@ export default function Index() {
|
||||
e.preventDefault();
|
||||
|
||||
if (template.actions.length > 0) {
|
||||
return toast.error(
|
||||
"You cannot delete a template that is linked to an action!",
|
||||
);
|
||||
return toast.error("You cannot delete a template that is linked to an action!");
|
||||
}
|
||||
|
||||
toast.promise(
|
||||
network.mock<Template, typeof UtilitySchemas.id>(
|
||||
project.secret,
|
||||
"DELETE",
|
||||
"/v1/templates",
|
||||
{
|
||||
id: template.id,
|
||||
},
|
||||
),
|
||||
network.mock<Template, typeof UtilitySchemas.id>(project.secret, "DELETE", "/v1/templates", {
|
||||
id: template.id,
|
||||
}),
|
||||
{
|
||||
loading: "Deleting your template",
|
||||
success: () => {
|
||||
@@ -205,23 +177,14 @@ export default function Index() {
|
||||
strokeWidth="1.5"
|
||||
d="M9.75 7.5V6.75C9.75 5.64543 10.6454 4.75 11.75 4.75H12.25C13.3546 4.75 14.25 5.64543 14.25 6.75V7.5"
|
||||
/>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
d="M5 7.75H19"
|
||||
/>
|
||||
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.5" d="M5 7.75H19" />
|
||||
</svg>
|
||||
Delete
|
||||
</button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<form
|
||||
onSubmit={handleSubmit(update)}
|
||||
className="grid gap-6 sm:grid-cols-6"
|
||||
>
|
||||
<form onSubmit={handleSubmit(update)} className="grid gap-6 sm:grid-cols-6">
|
||||
<Input
|
||||
className={"sm:col-span-4"}
|
||||
label={"Subject"}
|
||||
@@ -231,36 +194,25 @@ export default function Index() {
|
||||
/>
|
||||
|
||||
<div className={"sm:col-span-2"}>
|
||||
<label
|
||||
htmlFor={"type"}
|
||||
className="flex items-center text-sm font-medium text-neutral-700"
|
||||
>
|
||||
<label htmlFor={"type"} className="flex items-center text-sm font-medium text-neutral-700">
|
||||
Type
|
||||
<Tooltip
|
||||
content={
|
||||
<>
|
||||
<p className={"mb-2 text-base font-semibold"}>
|
||||
What type of email is this?
|
||||
</p>
|
||||
<p className={"mb-2 text-base font-semibold"}>What type of email is this?</p>
|
||||
<ul className={"list-inside"}>
|
||||
<li className={"mb-6"}>
|
||||
<span className={"font-semibold"}>Marketing</span>
|
||||
<br />
|
||||
Promotional emails with a Plunk-hosted unsubscribe
|
||||
link
|
||||
Promotional emails with a Plunk-hosted unsubscribe link
|
||||
<br />
|
||||
<span className={"text-neutral-400"}>
|
||||
(e.g. welcome emails, promotions)
|
||||
</span>
|
||||
<span className={"text-neutral-400"}>(e.g. welcome emails, promotions)</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className={"font-semibold"}>Transactional</span>
|
||||
<br />
|
||||
Mission critical emails <br />
|
||||
<span className={"text-neutral-400"}>
|
||||
{" "}
|
||||
(e.g. email verification, password reset)
|
||||
</span>
|
||||
<span className={"text-neutral-400"}> (e.g. email verification, password reset)</span>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
@@ -275,9 +227,7 @@ export default function Index() {
|
||||
/>
|
||||
</label>
|
||||
<Dropdown
|
||||
onChange={(t) =>
|
||||
setValue("type", t as "MARKETING" | "TRANSACTIONAL")
|
||||
}
|
||||
onChange={(t) => setValue("type", t as "MARKETING" | "TRANSACTIONAL")}
|
||||
values={[
|
||||
{ name: "Marketing", value: "MARKETING" },
|
||||
{ name: "Transactional", value: "TRANSACTIONAL" },
|
||||
|
||||
@@ -20,8 +20,7 @@ export default function Index() {
|
||||
<Alert type={"info"} title={"Need a hand?"}>
|
||||
<div className={"mt-3 grid items-center sm:grid-cols-4"}>
|
||||
<p className={"sm:col-span-3"}>
|
||||
Want us to help you get started? We can help you build your
|
||||
first action in less than 5 minutes.
|
||||
Want us to help you get started? We can help you build your first action in less than 5 minutes.
|
||||
</p>
|
||||
|
||||
<Link
|
||||
@@ -59,11 +58,7 @@ export default function Index() {
|
||||
{templates ? (
|
||||
templates.length > 0 ? (
|
||||
<>
|
||||
<div
|
||||
className={
|
||||
"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3"
|
||||
}
|
||||
>
|
||||
<div className={"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3"}>
|
||||
{templates
|
||||
.sort((a, b) => {
|
||||
if (a.actions.length > 0 && b.actions.length === 0) {
|
||||
@@ -93,16 +88,10 @@ export default function Index() {
|
||||
</span>
|
||||
<div className="flex-1 truncate">
|
||||
<div className="flex items-center space-x-3">
|
||||
<h3 className="truncate text-sm font-medium text-neutral-800">
|
||||
{t.subject}
|
||||
</h3>
|
||||
{t.actions.length > 0 && (
|
||||
<Badge type={"success"}>Active</Badge>
|
||||
)}
|
||||
<h3 className="truncate text-sm font-medium text-neutral-800">{t.subject}</h3>
|
||||
{t.actions.length > 0 && <Badge type={"success"}>Active</Badge>}
|
||||
</div>
|
||||
<p className="mt-1 truncate text-sm text-neutral-500">
|
||||
Last edited {dayjs().to(t.updatedAt)}
|
||||
</p>
|
||||
<p className="mt-1 truncate text-sm text-neutral-500">Last edited {dayjs().to(t.updatedAt)}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
@@ -112,12 +101,7 @@ export default function Index() {
|
||||
href={`/templates/${t.id}`}
|
||||
className="relative -mr-px inline-flex w-0 flex-1 items-center justify-center rounded-bl border border-transparent py-4 text-sm font-medium text-neutral-800 transition hover:bg-neutral-50 hover:text-neutral-700"
|
||||
>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
@@ -147,12 +131,7 @@ export default function Index() {
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Empty
|
||||
title={"No templates here"}
|
||||
description={
|
||||
"Try creating a new email blueprint for your actions"
|
||||
}
|
||||
/>
|
||||
<Empty title={"No templates here"} description={"Try creating a new email blueprint for your actions"} />
|
||||
</>
|
||||
)
|
||||
) : (
|
||||
|
||||
@@ -6,14 +6,7 @@ import { useRouter } from "next/router";
|
||||
import React from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
Card,
|
||||
Dropdown,
|
||||
Editor,
|
||||
FullscreenLoader,
|
||||
Input,
|
||||
Tooltip,
|
||||
} from "../../components";
|
||||
import { Card, Dropdown, Editor, FullscreenLoader, Input, Tooltip } from "../../components";
|
||||
import { Dashboard } from "../../layouts";
|
||||
import { useActiveProject } from "../../lib/hooks/projects";
|
||||
import { useTemplates } from "../../lib/hooks/templates";
|
||||
@@ -63,14 +56,9 @@ export default function Index() {
|
||||
|
||||
const create = async (data: TemplateValues) => {
|
||||
toast.promise(
|
||||
network.mock<Template, typeof TemplateSchemas.create>(
|
||||
project.secret,
|
||||
"POST",
|
||||
"/v1/templates",
|
||||
{
|
||||
...data,
|
||||
},
|
||||
),
|
||||
network.mock<Template, typeof TemplateSchemas.create>(project.secret, "POST", "/v1/templates", {
|
||||
...data,
|
||||
}),
|
||||
{
|
||||
loading: "Creating new template",
|
||||
success: () => {
|
||||
@@ -88,14 +76,8 @@ export default function Index() {
|
||||
return (
|
||||
<>
|
||||
<Dashboard>
|
||||
<Card
|
||||
title={"Create a new template"}
|
||||
description={"Reusable blueprints of your emails"}
|
||||
>
|
||||
<form
|
||||
onSubmit={handleSubmit(create)}
|
||||
className="grid gap-6 sm:grid-cols-6"
|
||||
>
|
||||
<Card title={"Create a new template"} description={"Reusable blueprints of your emails"}>
|
||||
<form onSubmit={handleSubmit(create)} className="grid gap-6 sm:grid-cols-6">
|
||||
<Input
|
||||
className={"sm:col-span-4"}
|
||||
label={"Subject"}
|
||||
@@ -105,36 +87,25 @@ export default function Index() {
|
||||
/>
|
||||
|
||||
<div className={"sm:col-span-2"}>
|
||||
<label
|
||||
htmlFor={"type"}
|
||||
className="flex items-center text-sm font-medium text-neutral-700"
|
||||
>
|
||||
<label htmlFor={"type"} className="flex items-center text-sm font-medium text-neutral-700">
|
||||
Type
|
||||
<Tooltip
|
||||
content={
|
||||
<>
|
||||
<p className={"mb-2 text-base font-semibold"}>
|
||||
What type of email is this?
|
||||
</p>
|
||||
<p className={"mb-2 text-base font-semibold"}>What type of email is this?</p>
|
||||
<ul className={"list-inside"}>
|
||||
<li className={"mb-6"}>
|
||||
<span className={"font-semibold"}>Marketing</span>
|
||||
<br />
|
||||
Promotional emails with a Plunk-hosted unsubscribe
|
||||
link
|
||||
Promotional emails with a Plunk-hosted unsubscribe link
|
||||
<br />
|
||||
<span className={"text-neutral-400"}>
|
||||
(e.g. welcome emails, promotions)
|
||||
</span>
|
||||
<span className={"text-neutral-400"}>(e.g. welcome emails, promotions)</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className={"font-semibold"}>Transactional</span>
|
||||
<br />
|
||||
Mission critical emails <br />
|
||||
<span className={"text-neutral-400"}>
|
||||
{" "}
|
||||
(e.g. email verification, password reset)
|
||||
</span>
|
||||
<span className={"text-neutral-400"}> (e.g. email verification, password reset)</span>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
@@ -149,9 +120,7 @@ export default function Index() {
|
||||
/>
|
||||
</label>
|
||||
<Dropdown
|
||||
onChange={(t) =>
|
||||
setValue("type", t as "MARKETING" | "TRANSACTIONAL")
|
||||
}
|
||||
onChange={(t) => setValue("type", t as "MARKETING" | "TRANSACTIONAL")}
|
||||
values={[
|
||||
{ name: "Marketing", value: "MARKETING" },
|
||||
{ name: "Transactional", value: "TRANSACTIONAL" },
|
||||
|
||||
Reference in New Issue
Block a user