Last active
March 14, 2022 02:20
-
-
Save tsukhu/31bf1d0a6b6154cdbec5c1cbfcacad32 to your computer and use it in GitHub Desktop.
Tailwind version of the remix.run newsletter subscription sample
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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="[email protected]" | |
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 : <> </>} | |
</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