diff --git a/README.md b/README.md index edc8a010a..0a57fcb4a 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ Below are the reusable packages that can be shared across multiple applications - **`@kit/billing-gateway`**: Billing gateway package that defines the schema and logic for managing payment gateways - **`@kit/stripe`**: Stripe package that defines the schema and logic for managing Stripe. This is used by the `@kit/billing-gateway` package and abstracts the Stripe API. - **`@kit/lemon-squeezy`**: Lemon Squeezy package that defines the schema and logic for managing Lemon Squeezy. This is used by the `@kit/billing-gateway` package and abstracts the Lemon Squeezy API. -- **`@kit/emails`**: Here we define the email templates using the `react.email` package. +- **`@kit/email-templates`**: Here we define the email templates using the `react.email` package. - **`@kit/mailers`**: Mailer package that abstracts the email service provider (e.g., Resend, Cloudflare, SendGrid, Mailgun, etc.) And features that can be added to the application: diff --git a/apps/web/config/app.config.ts b/apps/web/config/app.config.ts index 8430b0b56..7c3b715fb 100644 --- a/apps/web/config/app.config.ts +++ b/apps/web/config/app.config.ts @@ -36,7 +36,7 @@ const AppConfigSchema = z.object({ }); const appConfig = AppConfigSchema.parse({ - name: 'Awesomely', + name: process.env.NEXT_PUBLIC_PRODUCT_NAME, title: 'Awesomely - Your SaaS Title', description: 'Your SaaS Description', url: process.env.NEXT_PUBLIC_SITE_URL, diff --git a/apps/web/middleware.ts b/apps/web/middleware.ts index d75fa085f..d18f3e3b0 100644 --- a/apps/web/middleware.ts +++ b/apps/web/middleware.ts @@ -128,9 +128,12 @@ function getPatterns() { handler: async (req: NextRequest, res: NextResponse) => { const supabase = createMiddlewareClient(req, res); const { data } = await supabase.auth.getSession(); + + // check if we need to verify MFA (user is authenticated but needs to verify MFA) const isVerifyMfa = req.nextUrl.pathname === pathsConfig.auth.verifyMfa; - // If user is logged in, redirect to home page. + // If user is logged in and does not need to verify MFA, + // redirect to home page. if (data.session && !isVerifyMfa) { return NextResponse.redirect( new URL(pathsConfig.app.home, req.nextUrl.origin).href, @@ -157,10 +160,6 @@ function getPatterns() { const requiresMultiFactorAuthentication = await checkRequiresMultiFactorAuthentication(supabase); - console.log({ - requiresMultiFactorAuthentication, - }); - // If user requires multi-factor authentication, redirect to MFA page. if (requiresMultiFactorAuthentication) { return NextResponse.redirect( diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index be6ba1124..d7667fad2 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -15,6 +15,7 @@ const INTERNAL_PACKAGES = [ '@kit/billing', '@kit/billing-gateway', '@kit/stripe', + '@kit/email-templates', ]; /** @type {import('next').NextConfig} */ diff --git a/apps/web/package.json b/apps/web/package.json index 6a51a6714..af471b38c 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -22,7 +22,7 @@ "@kit/auth": "^0.1.0", "@kit/billing": "^0.1.0", "@kit/billing-gateway": "^0.1.0", - "@kit/emails": "^0.1.0", + "@kit/email-templates": "^0.1.0", "@kit/i18n": "^0.1.0", "@kit/mailers": "^0.1.0", "@kit/shared": "^0.1.0", @@ -32,7 +32,7 @@ "@next/mdx": "^14.1.0", "@radix-ui/react-icons": "^1.3.0", "@supabase/ssr": "^0.1.0", - "@supabase/supabase-js": "^2.39.8", + "@supabase/supabase-js": "^2.40.0", "@tanstack/react-query": "5.28.6", "@tanstack/react-query-next-experimental": "^5.28.6", "@tanstack/react-table": "^8.11.3", @@ -47,7 +47,7 @@ "next-themes": "^0.2.1", "react": "18.2.0", "react-dom": "18.2.0", - "react-hook-form": "^7.51.1", + "react-hook-form": "^7.51.2", "react-i18next": "^14.1.0", "recharts": "^2.10.3", "rehype-autolink-headings": "^7.1.0", diff --git a/apps/web/public/locales/en/account.json b/apps/web/public/locales/en/account.json index feca5d60e..8cf3d3ca4 100644 --- a/apps/web/public/locales/en/account.json +++ b/apps/web/public/locales/en/account.json @@ -34,6 +34,7 @@ "currentPassword": "Current Password", "newPassword": "New Password", "repeatPassword": "Repeat New Password", + "repeatPasswordDescription": "Please repeat your new password to confirm it", "yourPassword": "Your Password", "updatePasswordSubmitLabel": "Update Password", "updateEmailCardTitle": "Update your Email", diff --git a/packages/billing-gateway/package.json b/packages/billing-gateway/package.json index a524476cb..0fc405faa 100644 --- a/packages/billing-gateway/package.json +++ b/packages/billing-gateway/package.json @@ -19,7 +19,7 @@ "@kit/stripe": "0.1.0", "@kit/supabase": "^0.1.0", "@kit/ui": "0.1.0", - "@supabase/supabase-js": "^2.39.8", + "@supabase/supabase-js": "^2.40.0", "lucide-react": "^0.363.0", "zod": "^3.22.4" }, @@ -33,7 +33,7 @@ "@kit/tailwind-config": "0.1.0", "@kit/tsconfig": "0.1.0", "@kit/ui": "*", - "@supabase/supabase-js": "^2.39.8", + "@supabase/supabase-js": "^2.40.0", "lucide-react": "^0.363.0", "zod": "^3.22.4" }, diff --git a/packages/emails/README.md b/packages/email-templates/README.md similarity index 86% rename from packages/emails/README.md rename to packages/email-templates/README.md index 9a713ef2a..dbd6ada88 100644 --- a/packages/emails/README.md +++ b/packages/email-templates/README.md @@ -1,4 +1,4 @@ -# Emails - @kit/emails +# Emails - @kit/email-templates This package is responsible for managing email templates using the react.email library. diff --git a/packages/emails/package.json b/packages/email-templates/package.json similarity index 95% rename from packages/emails/package.json rename to packages/email-templates/package.json index f7084ab12..a6a9260c5 100644 --- a/packages/emails/package.json +++ b/packages/email-templates/package.json @@ -1,5 +1,5 @@ { - "name": "@kit/emails", + "name": "@kit/email-templates", "private": true, "version": "0.1.0", "scripts": { diff --git a/packages/emails/src/account-delete.email.tsx b/packages/email-templates/src/account-delete.email.tsx similarity index 100% rename from packages/emails/src/account-delete.email.tsx rename to packages/email-templates/src/account-delete.email.tsx diff --git a/packages/emails/src/index.ts b/packages/email-templates/src/index.ts similarity index 100% rename from packages/emails/src/index.ts rename to packages/email-templates/src/index.ts diff --git a/packages/emails/src/invite.email.tsx b/packages/email-templates/src/invite.email.tsx similarity index 100% rename from packages/emails/src/invite.email.tsx rename to packages/email-templates/src/invite.email.tsx diff --git a/packages/emails/tsconfig.json b/packages/email-templates/tsconfig.json similarity index 100% rename from packages/emails/tsconfig.json rename to packages/email-templates/tsconfig.json diff --git a/packages/features/accounts/package.json b/packages/features/accounts/package.json index 4e6d1eedd..442dfa2df 100644 --- a/packages/features/accounts/package.json +++ b/packages/features/accounts/package.json @@ -16,6 +16,8 @@ }, "devDependencies": { "@kit/billing-gateway": "*", + "@kit/email-templates": "*", + "@kit/mailers": "*", "@kit/eslint-config": "0.2.0", "@kit/prettier-config": "0.1.0", "@kit/shared": "*", @@ -23,6 +25,7 @@ "@kit/tailwind-config": "0.1.0", "@kit/tsconfig": "0.1.0", "@kit/ui": "*", + "@hookform/resolvers": "^3.3.4", "@radix-ui/react-icons": "^1.3.0", "lucide-react": "^0.363.0", "react-hook-form": "^7.51.2", diff --git a/packages/features/accounts/src/components/personal-account-settings/account-danger-zone.tsx b/packages/features/accounts/src/components/personal-account-settings/account-danger-zone.tsx index baa3309aa..932bd01dd 100644 --- a/packages/features/accounts/src/components/personal-account-settings/account-danger-zone.tsx +++ b/packages/features/accounts/src/components/personal-account-settings/account-danger-zone.tsx @@ -1,17 +1,23 @@ 'use client'; +import { useFormStatus } from 'react-dom'; + +import { zodResolver } from '@hookform/resolvers/zod'; import { ExclamationTriangleIcon } from '@radix-ui/react-icons'; import { useForm } from 'react-hook-form'; +import { z } from 'zod'; import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert'; -import { Button } from '@kit/ui/button'; import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogTrigger, -} from '@kit/ui/dialog'; + AlertDialog, + AlertDialogCancel, + AlertDialogContent, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from '@kit/ui/alert-dialog'; +import { Button } from '@kit/ui/button'; import { ErrorBoundary } from '@kit/ui/error-boundary'; import { Form, FormControl, FormItem, FormLabel } from '@kit/ui/form'; import { Input } from '@kit/ui/input'; @@ -20,10 +26,6 @@ import { Trans } from '@kit/ui/trans'; import { deletePersonalAccountAction } from '../../server/personal-accounts-server-actions'; export function AccountDangerZone() { - return ; -} - -function DeleteAccountContainer() { return (
@@ -45,30 +47,39 @@ function DeleteAccountContainer() { function DeleteAccountModal() { return ( - - + + - + - - - + e.preventDefault()}> + + - - + + }> - - + + ); } function DeleteAccountForm() { - const form = useForm(); + const form = useForm({ + resolver: zodResolver( + z.object({ + confirmation: z.string().refine((value) => value === 'DELETE'), + }), + ), + defaultValues: { + confirmation: '', + }, + }); return (
@@ -110,17 +121,25 @@ function DeleteAccountForm() {
-
+ + + + + -
+ ); } function DeleteAccountSubmitButton() { + const { pending } = useFormStatus(); + return ( -
- - ); -} - -function EmailOtpForm({ - shouldCreateUser, - onSuccess, -}: React.PropsWithChildren<{ - shouldCreateUser: boolean; - onSuccess: (email: string) => void; -}>) { - const signInWithOtpMutation = useSignInWithOtp(); - - return ( -
{ - event.preventDefault(); - - const email = event.currentTarget.email.value; - - await signInWithOtpMutation.mutateAsync({ - email, - options: { - shouldCreateUser, - }, - }); - - onSuccess(email); - }} - > -
- - - -
-
- ); -} diff --git a/packages/features/team-accounts/package.json b/packages/features/team-accounts/package.json index 962a7a036..6f1fec1bd 100644 --- a/packages/features/team-accounts/package.json +++ b/packages/features/team-accounts/package.json @@ -13,7 +13,7 @@ }, "devDependencies": { "@kit/accounts": "*", - "@kit/emails": "*", + "@kit/email-templates": "*", "@kit/eslint-config": "0.2.0", "@kit/mailers": "*", "@kit/prettier-config": "0.1.0", @@ -22,12 +22,12 @@ "@kit/tailwind-config": "0.1.0", "@kit/tsconfig": "0.1.0", "@kit/ui": "*", - "@hookform/resolvers/zod": "1.0.0", + "@hookform/resolvers": "^3.3.4", "lucide-react": "^0.363.0" }, "peerDependencies": { "@kit/accounts": "0.1.0", - "@kit/emails": "0.1.0", + "@kit/email-templates": "0.1.0", "@kit/mailers": "0.1.0", "@kit/shared": "0.1.0", "@kit/supabase": "0.1.0", diff --git a/packages/features/team-accounts/src/services/account-invitations.service.ts b/packages/features/team-accounts/src/services/account-invitations.service.ts index cded7f533..22281c0bf 100644 --- a/packages/features/team-accounts/src/services/account-invitations.service.ts +++ b/packages/features/team-accounts/src/services/account-invitations.service.ts @@ -149,7 +149,9 @@ export class AccountInvitationsService { for (const invitation of responseInvitations) { const promise = async () => { try { - const { renderInviteEmail } = await import('@kit/emails'); + const { renderInviteEmail } = await import( + '../../../../email-templates' + ); const html = renderInviteEmail({ link: this.getInvitationLink(invitation.invite_token), diff --git a/packages/supabase/package.json b/packages/supabase/package.json index b15a8608e..c0b6eaa54 100644 --- a/packages/supabase/package.json +++ b/packages/supabase/package.json @@ -29,13 +29,13 @@ "@kit/tailwind-config": "0.1.0", "@kit/tsconfig": "0.1.0", "@supabase/ssr": "^0.1.0", - "@supabase/supabase-js": "^2.39.8", + "@supabase/supabase-js": "^2.40.0", "@tanstack/react-query": "5.28.6" }, "peerDependencies": { "@epic-web/invariant": "^1.0.0", "@supabase/ssr": "^0.1.0", - "@supabase/supabase-js": "^2.39.8", + "@supabase/supabase-js": "^2.40.0", "@tanstack/react-query": "^5.28.6" }, "eslintConfig": { diff --git a/packages/ui/package.json b/packages/ui/package.json index b5510c719..3186a8e45 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -9,6 +9,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "@hookform/resolvers": "^3.3.4", "@radix-ui/react-accordion": "1.1.2", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-avatar": "^1.0.4", @@ -38,7 +39,7 @@ "class-variance-authority": "^0.7.0", "date-fns": "^3.2.0", "lucide-react": "^0.363.0", - "react-hook-form": "^7.49.2", + "react-hook-form": "^7.51.2", "react-i18next": "^14.1.0", "sonner": "^1.4.41", "zod": "^3.22.4" @@ -58,7 +59,7 @@ "lucide-react": "^0.363.0", "prettier": "^3.2.4", "react-day-picker": "^8.10.0", - "react-hook-form": "^7.51.1", + "react-hook-form": "^7.51.2", "react-i18next": "^14.1.0", "sonner": "^1.4.41", "tailwindcss": "3.4.1", diff --git a/packages/ui/src/makerkit/mdx/mdx-renderer.tsx b/packages/ui/src/makerkit/mdx/mdx-renderer.tsx index fce708615..73931d83e 100644 --- a/packages/ui/src/makerkit/mdx/mdx-renderer.tsx +++ b/packages/ui/src/makerkit/mdx/mdx-renderer.tsx @@ -2,7 +2,7 @@ import type { MDXComponents } from 'mdx/types'; import { getMDXComponent } from 'next-contentlayer/hooks'; import Components from './mdx-components'; -// @ts-expect-error +// @ts-ignore import styles from './mdx-renderer.module.css'; export function Mdx({ diff --git a/packages/ui/src/shadcn/form.tsx b/packages/ui/src/shadcn/form.tsx index ebe0f40c7..335659df3 100644 --- a/packages/ui/src/shadcn/form.tsx +++ b/packages/ui/src/shadcn/form.tsx @@ -5,7 +5,7 @@ import { Slot } from '@radix-ui/react-slot'; import type { ControllerProps, FieldPath, FieldValues } from 'react-hook-form'; import { Controller, FormProvider, useFormContext } from 'react-hook-form'; -import { cn } from '../utils/cn'; +import { cn } from '../utils'; import { Label } from './label'; const Form = FormProvider; diff --git a/packages/ui/src/shadcn/input-otp.tsx b/packages/ui/src/shadcn/input-otp.tsx index 5648462b6..a626efdc9 100644 --- a/packages/ui/src/shadcn/input-otp.tsx +++ b/packages/ui/src/shadcn/input-otp.tsx @@ -36,7 +36,13 @@ const InputOTPSlot = React.forwardRef< React.ComponentPropsWithoutRef<'div'> & { index: number } >(({ index, className, ...props }, ref) => { const inputOTPContext = React.useContext(OTPInputContext); - const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]; + const slot = inputOTPContext.slots[index]; + + if (!slot) { + return null; + } + + const { char, isActive, hasFakeCaret } = slot; return (
=12.22.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 diff --git a/turbo.json b/turbo.json index 9ac375933..1fa92bd2a 100644 --- a/turbo.json +++ b/turbo.json @@ -55,6 +55,17 @@ "globalEnv": [ "SKIP_ENV_VALIDATION", "STRIPE_SECRET_KEY", - "STRIPE_WEBHOOK_SECRET" + "STRIPE_WEBHOOK_SECRET", + "NEXT_PUBLIC_PRODUCT_NAME", + "EMAIL_SENDER", + "EMAIL_PORT", + "EMAIL_HOST", + "EMAIL_TLS", + "EMAIL_USER", + "EMAIL_PASSWORD", + "SIGN_IN_PATH", + "SIGN_UP_PATH", + "TEAM_ACCOUNTS_HOME_PATH", + "INVITATION_PAGE_PATH" ] } \ No newline at end of file