diff --git a/apps/builder/src/features/auth/components/SignInForm.tsx b/apps/builder/src/features/auth/components/SignInForm.tsx index a922a730d..1e4e5e7c9 100644 --- a/apps/builder/src/features/auth/components/SignInForm.tsx +++ b/apps/builder/src/features/auth/components/SignInForm.tsx @@ -6,7 +6,10 @@ import { HStack, Text, Spinner, - Tooltip, + Alert, + Flex, + AlertIcon, + SlideFade, } from '@chakra-ui/react' import React, { ChangeEvent, FormEvent, useEffect } from 'react' import { useState } from 'react' @@ -78,11 +81,6 @@ export const SignInForm = ({ }) } else { setIsMagicLinkSent(true) - showToast({ - status: 'success', - title: 'Success!', - description: 'Check your inbox to sign in', - }) } setAuthLoading(false) } @@ -103,40 +101,54 @@ export const SignInForm = ({ ) return ( - - {providers?.email && ( + {!isMagicLinkSent && ( <> - Or with your email - - - - - - + + {providers?.email && ( + <> + Or with your email + + + + + + )} )} {router.query.error && ( )} + + + + + + + + A magic link email was sent. 🪄 + + Make sure to check your SPAM folder. + + + + + ) } diff --git a/apps/builder/src/pages/api/auth/[...nextauth].ts b/apps/builder/src/pages/api/auth/[...nextauth].ts index 3fbad4675..a75b0d18e 100644 --- a/apps/builder/src/pages/api/auth/[...nextauth].ts +++ b/apps/builder/src/pages/api/auth/[...nextauth].ts @@ -13,6 +13,7 @@ import { User } from 'db' import { env, getAtPath, isDefined, isNotEmpty } from 'utils' import { mockedUser } from '@/features/auth' import { getNewUserInvitations } from '@/features/auth/api' +import { sendVerificationRequest } from './sendVerificationRequest' const providers: Provider[] = [] @@ -42,6 +43,7 @@ if (isNotEmpty(env('SMTP_FROM')) && process.env.SMTP_AUTH_DISABLED !== 'true') }, }, from: env('SMTP_FROM'), + sendVerificationRequest, }) ) diff --git a/apps/builder/src/pages/api/auth/sendVerificationRequest.ts b/apps/builder/src/pages/api/auth/sendVerificationRequest.ts new file mode 100644 index 000000000..50b04fb05 --- /dev/null +++ b/apps/builder/src/pages/api/auth/sendVerificationRequest.ts @@ -0,0 +1,16 @@ +import { EmailConfig } from 'next-auth/providers/email' +import { sendMagicLinkEmail } from 'emails' + +type Props = { + identifier: string + url: string + provider: Partial> +} + +export const sendVerificationRequest = async ({ identifier, url }: Props) => { + try { + await sendMagicLinkEmail({ url, to: identifier }) + } catch (err) { + throw new Error(`Email(s) could not be sent`) + } +} diff --git a/packages/emails/src/components/Button.tsx b/packages/emails/src/components/Button.tsx index cbf5e9beb..91a84e8a3 100644 --- a/packages/emails/src/components/Button.tsx +++ b/packages/emails/src/components/Button.tsx @@ -1,14 +1,14 @@ import React from 'react' -import { MjmlButton } from '@faire/mjml-react' +import { IMjmlButtonProps, MjmlButton } from '@faire/mjml-react' import { blue, grayLight } from '../theme' import { leadingTight, textBase, borderBase } from '../theme' type ButtonProps = { link: string children: React.ReactNode -} +} & IMjmlButtonProps -export const Button = ({ link, children }: ButtonProps) => ( +export const Button = ({ link, children, ...props }: ButtonProps) => ( ( backgroundColor={blue} color={grayLight} borderRadius={borderBase} + {...props} > {children} diff --git a/packages/emails/src/emails/MagicLinkEmail.tsx b/packages/emails/src/emails/MagicLinkEmail.tsx new file mode 100644 index 000000000..9c5ec7e59 --- /dev/null +++ b/packages/emails/src/emails/MagicLinkEmail.tsx @@ -0,0 +1,55 @@ +import React, { ComponentProps } from 'react' +import { + Mjml, + MjmlBody, + MjmlSection, + MjmlColumn, + MjmlSpacer, +} from '@faire/mjml-react' +import { render } from '@faire/mjml-react/utils/render' +import { HeroImage, Text, Button, Head } from '../components' +import { SendMailOptions } from 'nodemailer' +import { sendEmail } from '../sendEmail' + +type Props = { + url: string +} + +export const MagicLinkEmail = ({ url }: Props) => ( + + + + + + + + + + + Here is your magic link 👇 + + + + If you didn't request this, please ignore this email. + + + Best, +
- Typebot Team. +
+
+
+
+
+) + +export const sendMagicLinkEmail = ({ + to, + ...props +}: Pick & ComponentProps) => + sendEmail({ + to, + subject: 'Sign in to Typebot', + html: render().html, + }) diff --git a/packages/emails/src/emails/index.ts b/packages/emails/src/emails/index.ts index 3400aba2b..b2a863cb8 100644 --- a/packages/emails/src/emails/index.ts +++ b/packages/emails/src/emails/index.ts @@ -5,3 +5,4 @@ export * from './GuestInvitationEmail' export * from './ReachedChatsLimitEmail' export * from './ReachedStorageLimitEmail' export * from './WorkspaceMemberInvitationEmail' +export * from './MagicLinkEmail' diff --git a/packages/emails/src/preview.tsx b/packages/emails/src/preview.tsx index 23bf19fbf..a09126107 100644 --- a/packages/emails/src/preview.tsx +++ b/packages/emails/src/preview.tsx @@ -10,6 +10,7 @@ import { ReachedStorageLimitEmail, WorkspaceMemberInvitation, } from './emails' +import { MagicLinkEmail } from './emails/MagicLinkEmail' const createDistFolder = () => { const dist = path.resolve(__dirname, 'dist') @@ -91,6 +92,10 @@ const createHtmlFile = () => { /> ).html ) + fs.writeFileSync( + path.resolve(__dirname, 'dist', 'magicLink.html'), + render().html + ) } createDistFolder()