Personal Website for @jaspermayone.com
jaspermayone.com
1"use client";
2import { emails } from "@/lib/defs";
3import styles from "@/styles/Misc.module.css";
4import { useState, type FormEvent } from "react";
5import { Button } from "./ui/button";
6import { Input } from "./ui/input";
7
8// Emails from defs.ts plus any additional aliases not in the main list
9const predefinedEmails = [
10 ...emails.map((e) => e.address),
11 "jasperphoenixmayone@gmail.com",
12 "jasper.mayone@jaspermayone.com",
13 "jasper.mayone.skiskate@gmail.com",
14];
15
16export default function Email() {
17 const [email, setEmail] = useState("");
18 const [submitted, setSubmitted] = useState(false);
19 const [error, setError] = useState<string | null>(null);
20 const [woahThere, setWoahThere] = useState<boolean>(false);
21 const [isLoading, setIsLoading] = useState<boolean>(false);
22
23 async function onSubmit(event: FormEvent<HTMLFormElement>) {
24 event.preventDefault();
25 setIsLoading(true);
26 setError(null);
27 setWoahThere(false);
28
29 if (predefinedEmails.includes(email)) {
30 setWoahThere(true);
31 setIsLoading(false);
32 return;
33 }
34
35 fetch("/api/email/new", {
36 method: "POST",
37 body: JSON.stringify({ email }),
38 headers: {
39 "Content-Type": "application/json",
40 },
41 })
42 .then((res) => res.json())
43 .then((data) => {
44 if (data.success) {
45 setSubmitted(true);
46 } else {
47 setError("Failed to submit. Please try again.");
48 }
49 })
50 .catch(() => {
51 setError("An error occurred during submission.");
52 })
53 .finally(() => {
54 setIsLoading(false);
55 });
56 }
57
58 const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
59 setEmail(e.target.value);
60 };
61
62 return (
63 <div className="mx-auto w-full max-w-6xl px-4">
64 {/* h2 with custom .ul class */}
65 <h2 className={styles.lightUl}>Newsletter</h2>
66 <p className="mb-4 text-sm text-gray-700 dark:text-white/70">
67 Subscribe to my newsletter to get <i>occasioal</i> updates on what
68 I'm up to.
69 </p>
70
71 {!submitted ? (
72 <form onSubmit={onSubmit} className="w-full">
73 <div className="flex w-full flex-col gap-3 sm:flex-row">
74 <Input
75 type="email"
76 placeholder="example@example.com"
77 className="flex-1 border-1 border-gray-300 text-sm outline-none focus:border-blue-400 focus:ring-blue-400"
78 value={email}
79 onChange={handleInputChange}
80 aria-label="email"
81 required
82 />
83 <Button
84 type="submit"
85 className="bg-blue-400 text-sm whitespace-nowrap"
86 aria-label="submit"
87 disabled={isLoading}
88 data-umami-event="newsletter_submit"
89 data-umami-event-email={email}
90 >
91 {isLoading ? "Submitting..." : "Submit"}
92 </Button>
93 </div>
94
95 {woahThere && (
96 <p className="mt-2 text-sm text-purple-500">
97 Slow down cowboy! You're not Jasper!
98 </p>
99 )}
100 {error && <p className="mt-2 text-sm text-red-500">{error}</p>}
101 </form>
102 ) : (
103 <p className="text-sm text-green-400">
104 Submitted! Be sure to look out for emails in the future!
105 </p>
106 )}
107 </div>
108 );
109}