Skip to content

Instantly share code, notes, and snippets.

@tsukhu
Last active March 14, 2022 02:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tsukhu/31bf1d0a6b6154cdbec5c1cbfcacad32 to your computer and use it in GitHub Desktop.
Save tsukhu/31bf1d0a6b6154cdbec5c1cbfcacad32 to your computer and use it in GitHub Desktop.
Tailwind version of the remix.run newsletter subscription sample
// Based on the Remix Single (https://www.youtube.com/watch?v=jd_bin5HPrw&list=PLXoynULbYuEDG2wBFSZ66b85EIspy3fy6)
import { Transition } from '@headlessui/react';
import { CheckIcon, RefreshIcon } from '@heroicons/react/outline';
import { useEffect, useRef } from 'react';
import {
ActionFunction,
Form,
Link,
useActionData,
useTransition,
} from 'remix';
export let action: ActionFunction = async ({ request }) => {
let formData = await request.formData();
let email = formData.get('email');
const API_KEY = process.env.CONVERT_KIT_API_KEY;
const FORM_ID = process.env.CONVERT_KIT_FORM_ID;
const API_URL = `https://api.convertkit.com/v3/forms/${FORM_ID}/subscribe`;
let res = await fetch(API_URL, {
method: 'post',
body: JSON.stringify({ email, api_key: API_KEY }),
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
});
return res.json();
};
export default function Subscription() {
let actionData = useActionData();
let transition = useTransition();
let state: 'idle' | 'success' | 'error' | 'submitting' = transition.submission
? 'submitting'
: actionData?.subscription
? 'success'
: actionData?.error
? 'error'
: 'idle';
let inputRef = useRef<HTMLInputElement>(null);
let successRef = useRef<HTMLHeadingElement>(null);
let mounted = useRef<boolean>(false);
useEffect(() => {
if (state === 'error') {
inputRef.current?.focus();
}
if (state === 'idle' && mounted.current) {
inputRef.current?.select();
}
if (state === 'success') {
successRef.current?.focus();
}
mounted.current = true;
}, [state]);
return (
<div className="flex flex-col items-center w-full h-full justify-center bg-[url('/bg.svg')] bg-cover">
<main className="flex p-2 items-center justify-center bg-white rounded-md shadow-md w-full max-w-lg h-full max-h-60 ">
<Transition
appear={true}
show={state !== 'success'}
enter="transition-opacity duration-300 ease-in"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="transition-opacity duration-150 ease-out"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Form
method="post"
replace
className={`text-center flex-col items-center justify-center ${
state === 'success' ? 'hidden' : 'flex'
}`}
>
<h2 className="outline-none mb-0 font-bold text-2xl text-gray-700">
Subscribe
</h2>
<p className="text-gray-700">Don't miss any of the action!</p>
<fieldset
className="gap-1 mt-8 flex"
disabled={state === 'submitting'}
>
<input
type="email"
name="email"
aria-describedby="error-message"
aria-label="email address"
ref={inputRef}
placeholder="you@example.com"
autoComplete="off"
className="px-8 py-2 rounded focus:outline-none focus:ring-sky-500 focus:shadow-sm border-gray-200 caret-gray-500"
/>
<button
type="submit"
className="w-40 captalize inline-flex space-x-2 items-center justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-sky-600 hover:bg-sky-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-sky-500"
>
<div>
{state === 'submitting' ? (
<RefreshIcon className="w-5 h-5 animate-spin" />
) : (
<CheckIcon className="w-5 h-5" />
)}
</div>
<div>{state === 'submitting' ? 'Submitting' : 'Subscribe'}</div>
</button>
</fieldset>
<p className="text-sm text-red-500 m-2" id="error-message">
{state === 'error' ? actionData.message : <>&nbsp;</>}
</p>
</Form>
</Transition>
<Transition
appear={true}
show={state === 'success'}
enter="transition-opacity duration-300 ease-in"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="transition-opacity duration-150 ease-out"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div
className={`text-center flex-col space-y-2 items-center justify-center ${
state !== 'success' ? 'hidden' : 'flex'
}`}
>
<h2
className="outline-none mb-0 font-bold text-2xl"
ref={successRef}
tabIndex={-1}
>
You're subscribed
</h2>
<p className="text-gray-700">
Please check your email to confirm your subscription.
</p>
<Link
to="."
className="p-2 font-semibold underline text-sky-700 hover:text-sky-800"
>
Start Over
</Link>
</div>
</Transition>
</main>
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment