Skip to content

Instantly share code, notes, and snippets.

@HectorBlisS
Last active December 20, 2022 03:01
Show Gist options
  • Save HectorBlisS/674e3a0e2b2c31cd73017bb9a8527e72 to your computer and use it in GitHub Desktop.
Save HectorBlisS/674e3a0e2b2c31cd73017bb9a8527e72 to your computer and use it in GitHub Desktop.
Flujo de suscripción
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);
});
};
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>
);
}
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