Last active
December 20, 2022 03:01
-
-
Save HectorBlisS/674e3a0e2b2c31cd73017bb9a8527e72 to your computer and use it in GitHub Desktop.
Flujo de suscripción
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
import jwt from 'jsonwebtoken'; | |
import nodemailer from 'nodemailer'; | |
export const verify = (token: string) => { | |
return new Promise((res) => { | |
jwt.verify(token, 'blissmo', (error, info) => { | |
if (error) { | |
return res({ message: error.message, isError: true }); | |
} | |
return res(info); | |
}); | |
}); | |
}; | |
const transporter = nodemailer.createTransport({ | |
service: 'gmail', | |
auth: { | |
user: 'fixtermailer@gmail.com', | |
pass: process.env.FIXTERMAILER_PASS, | |
}, | |
}); | |
export const sendToken = (email: string, lifeTime: number = 1) => { | |
const token = jwt.sign( | |
{ | |
email, | |
}, | |
'blissmo', | |
{ expiresIn: `${lifeTime}h` } | |
); | |
const link = `http://localhost:3000/suscripcion?token=${token}`; | |
const mailOptions = { | |
from: 'fixtermailer@gmail.com', | |
to: email, | |
subject: '🍿Confirma tu cuenta🍺', | |
html: `<a rel="noreferrer" target="_blank" href="${link}">Confirma tu cuenta aquí</a>`, | |
}; | |
transporter.sendMail(mailOptions, (error, info) => { | |
console.error(error); | |
console.log(info); | |
}); | |
}; |
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
import { | |
type LoaderFunction, | |
type ActionFunction, | |
json, | |
} from '@remix-run/node'; | |
import { Form, useActionData, useLoaderData } from '@remix-run/react'; | |
import { commitSession, getSession } from '~/sessions'; | |
import { sendToken, verify } from '~/utils/sendMail.server'; | |
import useEmojieConfetti from '~/components/useEmojiConfetti'; | |
import { useEffect } from 'react'; | |
// 2. Action to generate token and send email | |
// 2.1 utility functions | |
export const action: ActionFunction = async ({ request }) => { | |
const formData = await request.formData(); | |
const email = formData.get('email') as string; | |
if (!email) return null; | |
sendToken(email); | |
return true; | |
}; | |
type LoaderData = { | |
success: boolean; | |
}; | |
// 3. Loader to verify token (utility function) | |
export const loader: LoaderFunction = async ({ request }) => { | |
const url = new URL(request.url); | |
const token = url.searchParams.get('token'); | |
if (!token) return { success: false }; | |
const decoded = await verify(token); | |
console.log('bef:', decoded); | |
if (decoded.isError) return { success: false, message: decoded.message }; // @TODO: | |
console.log('dec:', decoded); | |
//informar al usuario que el token no es valido | |
// ir a la DB y confirmar la cuenta | |
const session = await getSession(request.headers.get('Cookie')); | |
session.set('email', decoded.email); | |
return json( | |
{ success: true }, | |
{ | |
headers: { | |
'Set-Cookie': await commitSession(session), | |
}, | |
} | |
); | |
}; | |
// 3.1 Save into DB and set cookie | |
export default function Suscripcion() { | |
// 5. UX details like disabled button | |
const sent = useActionData(); | |
const confetti = useEmojieConfetti(); | |
// 4. using loader data to celebrate | |
const { success, message } = useLoaderData<LoaderData>(); | |
useEffect(() => { | |
if (success) { | |
confetti.start(); | |
} | |
}, [success]); | |
if (success) { | |
return ( | |
<section className='flex flex-col py-20 items-center'> | |
<h2 className='text-4xl font-bold text-blue-500'> | |
Tu cuenta ha sido confirmada exitosamente | |
</h2> | |
<button className='text-lg bg-blue-500 py-2 px-6 rounded-md text-white disabled:cursor-not-allowed disabled:bg-gray-400'> | |
Ver el recurso | |
</button> | |
</section> | |
); | |
} | |
// 1.- Set the form | |
return ( | |
<div className='bg-blue-100'> | |
<section className='h-screen max-w-xl mx-auto py-20 flex flex-col items-center justify-center '> | |
{message && ( | |
<h2 className='text-4xl font-bold text-red-500'>{message}</h2> | |
)} | |
<Form | |
method='post' | |
className='flex items-center py-20 justify-center gap-2' | |
> | |
<input | |
required | |
type='email' | |
name='email' | |
className='px-6 text-lg bg-blue-200 rounded-md placeholder-blue-500 py-2' | |
placeholder='Escriibe tu correo' | |
/> | |
<button | |
// disabled={transition.state !== 'idle'} | |
type='submit' | |
className='text-lg bg-blue-500 py-2 px-6 rounded-md text-white disabled:cursor-not-allowed disabled:bg-gray-400' | |
> | |
Suscribirme | |
</button> | |
</Form> | |
<br /> | |
<p className='text-center text-blue-500'> | |
{sent && 'Revisa tu correo'} | |
</p> | |
</section> | |
</div> | |
); | |
} |
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
import JSConfetti from 'js-confetti'; | |
export default function useEmojieConfetti(emojis?: string[]) { | |
const imgs = emojis || ['🪅', '🍿', '🍾', '🍕']; | |
const start = () => { | |
const jsConfetti = new JSConfetti(); | |
jsConfetti.addConfetti({ | |
emojis: imgs, | |
}); | |
setTimeout(() => { | |
jsConfetti.addConfetti(); | |
}, 1000); | |
}; | |
return { start }; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment