Invite prefill email (#43)
* Add prepopulation of email field in sign-up form * Updated packages
This commit is contained in:
committed by
GitHub
parent
4f0e6b9bbb
commit
21f42f14ce
@@ -1,13 +1,13 @@
|
||||
import { getOrder, getSubscription, getVariant } from '@lemonsqueezy/lemonsqueezy.js';
|
||||
|
||||
|
||||
import {
|
||||
getOrder,
|
||||
getSubscription,
|
||||
getVariant,
|
||||
} from '@lemonsqueezy/lemonsqueezy.js';
|
||||
|
||||
import { BillingConfig, BillingWebhookHandlerService } from '@kit/billing';
|
||||
import { getLogger } from '@kit/shared/logger';
|
||||
import { Database } from '@kit/supabase/database';
|
||||
|
||||
|
||||
|
||||
import { getLemonSqueezyEnv } from '../schema/lemon-squeezy-server-env.schema';
|
||||
import { OrderWebhook } from '../types/order-webhook';
|
||||
import { SubscriptionInvoiceWebhook } from '../types/subscription-invoice-webhook';
|
||||
@@ -16,7 +16,6 @@ import { initializeLemonSqueezyClient } from './lemon-squeezy-sdk';
|
||||
import { createLemonSqueezySubscriptionPayloadBuilderService } from './lemon-squeezy-subscription-payload-builder.service';
|
||||
import { createHmac } from './verify-hmac';
|
||||
|
||||
|
||||
type UpsertSubscriptionParams =
|
||||
Database['public']['Functions']['upsert_subscription']['Args'] & {
|
||||
line_items: Array<LineItem>;
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"@kit/ui": "workspace:^",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@supabase/supabase-js": "^2.44.3",
|
||||
"@tanstack/react-query": "5.50.1",
|
||||
"@tanstack/react-query": "5.51.1",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"lucide-react": "^0.407.0",
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from './user-workspace-context';
|
||||
export * from './user-workspace-context';
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"@makerkit/data-loader-supabase-core": "^0.0.8",
|
||||
"@makerkit/data-loader-supabase-nextjs": "^1.2.3",
|
||||
"@supabase/supabase-js": "^2.44.3",
|
||||
"@tanstack/react-query": "5.50.1",
|
||||
"@tanstack/react-query": "5.51.1",
|
||||
"@tanstack/react-table": "^8.19.2",
|
||||
"@types/react": "^18.3.3",
|
||||
"lucide-react": "^0.407.0",
|
||||
|
||||
@@ -8,7 +8,6 @@ import { Button } from '@kit/ui/button';
|
||||
import { Heading } from '@kit/ui/heading';
|
||||
import { If } from '@kit/ui/if';
|
||||
import { ProfileAvatar } from '@kit/ui/profile-avatar';
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
"@kit/tailwind-config": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@kit/ui": "workspace:^",
|
||||
"@marsidev/react-turnstile": "^0.7.1",
|
||||
"@marsidev/react-turnstile": "^0.7.2",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@supabase/supabase-js": "^2.44.3",
|
||||
"@tanstack/react-query": "5.50.1",
|
||||
"@tanstack/react-query": "5.51.1",
|
||||
"@types/react": "^18.3.3",
|
||||
"lucide-react": "^0.407.0",
|
||||
"next": "14.2.5",
|
||||
|
||||
@@ -28,10 +28,14 @@ export function MagicLinkAuthContainer({
|
||||
inviteToken,
|
||||
redirectUrl,
|
||||
shouldCreateUser,
|
||||
defaultValues,
|
||||
}: {
|
||||
inviteToken?: string;
|
||||
redirectUrl: string;
|
||||
shouldCreateUser: boolean;
|
||||
defaultValues?: {
|
||||
email: string;
|
||||
};
|
||||
}) {
|
||||
const { captchaToken, resetCaptchaToken } = useCaptchaToken();
|
||||
const { t } = useTranslation();
|
||||
@@ -44,7 +48,7 @@ export function MagicLinkAuthContainer({
|
||||
}),
|
||||
),
|
||||
defaultValues: {
|
||||
email: '',
|
||||
email: defaultValues?.email ?? ''
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -14,11 +14,16 @@ import { AuthErrorAlert } from './auth-error-alert';
|
||||
import { PasswordSignUpForm } from './password-sign-up-form';
|
||||
|
||||
interface EmailPasswordSignUpContainerProps {
|
||||
defaultValues?: {
|
||||
email: string;
|
||||
};
|
||||
|
||||
onSignUp?: (userId?: string) => unknown;
|
||||
emailRedirectTo: string;
|
||||
}
|
||||
|
||||
export function EmailPasswordSignUpContainer({
|
||||
defaultValues,
|
||||
onSignUp,
|
||||
emailRedirectTo,
|
||||
}: EmailPasswordSignUpContainerProps) {
|
||||
@@ -72,7 +77,11 @@ export function EmailPasswordSignUpContainer({
|
||||
<If condition={!showVerifyEmailAlert}>
|
||||
<AuthErrorAlert error={signUpMutation.error} />
|
||||
|
||||
<PasswordSignUpForm onSubmit={onSignupRequested} loading={loading} />
|
||||
<PasswordSignUpForm
|
||||
onSubmit={onSignupRequested}
|
||||
loading={loading}
|
||||
defaultValues={defaultValues}
|
||||
/>
|
||||
</If>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -22,9 +22,14 @@ import { Trans } from '@kit/ui/trans';
|
||||
import { PasswordSignUpSchema } from '../schemas/password-sign-up.schema';
|
||||
|
||||
export function PasswordSignUpForm({
|
||||
defaultValues,
|
||||
onSubmit,
|
||||
loading,
|
||||
}: {
|
||||
defaultValues?: {
|
||||
email: string;
|
||||
};
|
||||
|
||||
onSubmit: (params: {
|
||||
email: string;
|
||||
password: string;
|
||||
@@ -37,7 +42,7 @@ export function PasswordSignUpForm({
|
||||
const form = useForm({
|
||||
resolver: zodResolver(PasswordSignUpSchema),
|
||||
defaultValues: {
|
||||
email: '',
|
||||
email: defaultValues?.email ?? '',
|
||||
password: '',
|
||||
repeatPassword: '',
|
||||
},
|
||||
|
||||
@@ -27,7 +27,8 @@ export function SignUpMethodsContainer(props: {
|
||||
inviteToken?: string;
|
||||
}) {
|
||||
const redirectUrl = getCallbackUrl(props);
|
||||
|
||||
const defaultValues = getDefaultValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<If condition={props.inviteToken}>
|
||||
@@ -35,7 +36,10 @@ export function SignUpMethodsContainer(props: {
|
||||
</If>
|
||||
|
||||
<If condition={props.providers.password}>
|
||||
<EmailPasswordSignUpContainer emailRedirectTo={redirectUrl} />
|
||||
<EmailPasswordSignUpContainer
|
||||
emailRedirectTo={redirectUrl}
|
||||
defaultValues={defaultValues}
|
||||
/>
|
||||
</If>
|
||||
|
||||
<If condition={props.providers.magicLink}>
|
||||
@@ -43,6 +47,7 @@ export function SignUpMethodsContainer(props: {
|
||||
inviteToken={props.inviteToken}
|
||||
redirectUrl={redirectUrl}
|
||||
shouldCreateUser={true}
|
||||
defaultValues={defaultValues}
|
||||
/>
|
||||
</If>
|
||||
|
||||
@@ -93,6 +98,23 @@ function getCallbackUrl(props: {
|
||||
return url.href;
|
||||
}
|
||||
|
||||
function getDefaultValues() {
|
||||
if (!isBrowser()) {
|
||||
return { email: '' };
|
||||
}
|
||||
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const inviteToken = searchParams.get('invite_token');
|
||||
|
||||
if (!inviteToken) {
|
||||
return { email: '' };
|
||||
}
|
||||
|
||||
return {
|
||||
email: searchParams.get('email') ?? '',
|
||||
};
|
||||
}
|
||||
|
||||
function InviteAlert() {
|
||||
return (
|
||||
<Alert variant={'info'}>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@kit/ui": "workspace:*",
|
||||
"@supabase/supabase-js": "^2.44.3",
|
||||
"@tanstack/react-query": "5.50.1",
|
||||
"@tanstack/react-query": "5.51.1",
|
||||
"@types/react": "^18.3.3",
|
||||
"lucide-react": "^0.407.0",
|
||||
"react": "18.3.1",
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@kit/ui": "workspace:^",
|
||||
"@supabase/supabase-js": "^2.44.3",
|
||||
"@tanstack/react-query": "5.50.1",
|
||||
"@tanstack/react-query": "5.51.1",
|
||||
"@tanstack/react-table": "^8.19.2",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
|
||||
@@ -5,4 +5,4 @@ export * from './invitations/account-invitations-table';
|
||||
export * from './settings/team-account-settings-container';
|
||||
export * from './invitations/accept-invitation-container';
|
||||
export * from './create-team-account-dialog';
|
||||
export * from './team-account-workspace-context';
|
||||
export * from './team-account-workspace-context';
|
||||
|
||||
@@ -102,9 +102,10 @@ class AccountInvitationsWebhookService {
|
||||
const { getMailer } = await import('@kit/mailers');
|
||||
|
||||
const mailer = await getMailer();
|
||||
const link = this.getInvitationLink(invitation.invite_token, invitation.email);
|
||||
|
||||
const { html, subject } = await renderInviteEmail({
|
||||
link: this.getInvitationLink(invitation.invite_token),
|
||||
link,
|
||||
invitedUserEmail: invitation.email,
|
||||
inviter: inviter.data.name ?? inviter.data.email ?? '',
|
||||
productName: env.productName,
|
||||
@@ -141,7 +142,14 @@ class AccountInvitationsWebhookService {
|
||||
}
|
||||
}
|
||||
|
||||
private getInvitationLink(token: string) {
|
||||
return new URL(env.invitePath, env.siteURL).href + `?invite_token=${token}`;
|
||||
private getInvitationLink(token: string, email: string) {
|
||||
const searchParams = new URLSearchParams({
|
||||
invite_token: token,
|
||||
email,
|
||||
}).toString();
|
||||
|
||||
const href = new URL(env.invitePath, env.siteURL).href;
|
||||
|
||||
return `${href}?${searchParams}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"@kit/shared": "workspace:^",
|
||||
"@kit/tailwind-config": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@tanstack/react-query": "5.50.1",
|
||||
"@tanstack/react-query": "5.51.1",
|
||||
"react-i18next": "^14.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"@supabase/gotrue-js": "2.64.3",
|
||||
"@supabase/ssr": "^0.4.0",
|
||||
"@supabase/supabase-js": "^2.44.3",
|
||||
"@tanstack/react-query": "5.50.1",
|
||||
"@tanstack/react-query": "5.51.1",
|
||||
"@types/react": "^18.3.3",
|
||||
"next": "14.2.5",
|
||||
"react": "18.3.1",
|
||||
|
||||
@@ -87,6 +87,12 @@ class AuthCallbackService {
|
||||
// correct page.
|
||||
url.pathname = params.joinTeamPath;
|
||||
searchParams.set('invite_token', inviteToken);
|
||||
|
||||
const emailParam = callbackUrl?.searchParams.get('email');
|
||||
|
||||
if (emailParam) {
|
||||
searchParams.set('email', emailParam);
|
||||
}
|
||||
}
|
||||
|
||||
if (token_hash && type) {
|
||||
@@ -138,7 +144,14 @@ class AuthCallbackService {
|
||||
// to join a team and we want to make sure they are redirected to the
|
||||
// correct page.
|
||||
if (inviteToken) {
|
||||
nextUrl = `${params.joinTeamPath}?invite_token=${inviteToken}`;
|
||||
const emailParam = searchParams.get('email');
|
||||
|
||||
const urlParams = new URLSearchParams({
|
||||
invite_token: inviteToken,
|
||||
email: emailParam ?? ''
|
||||
});
|
||||
|
||||
nextUrl = `${params.joinTeamPath}?${urlParams.toString()}`;
|
||||
}
|
||||
|
||||
if (authCode) {
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"@kit/tailwind-config": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@tanstack/react-query": "5.50.1",
|
||||
"@tanstack/react-query": "5.51.1",
|
||||
"@tanstack/react-table": "^8.19.2",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
|
||||
@@ -22,7 +22,7 @@ export function GlobalLoader({
|
||||
<If condition={displaySpinner}>
|
||||
<div
|
||||
className={
|
||||
'flex flex-1 flex-col items-center justify-center animate-in fade-in zoom-in-50 slide-in-from-bottom-8'
|
||||
'flex flex-1 flex-col items-center justify-center duration-500 animate-in fade-in zoom-in-80 slide-in-from-bottom-12'
|
||||
}
|
||||
>
|
||||
<LoadingOverlay displayLogo={displayLogo} fullPage={fullPage} />
|
||||
|
||||
@@ -12,11 +12,11 @@ import React, {
|
||||
} from 'react';
|
||||
|
||||
import { Slot, Slottable } from '@radix-ui/react-slot';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { Path, UseFormReturn } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { cn } from '../utils';
|
||||
import {useMutation} from "@tanstack/react-query";
|
||||
|
||||
interface MultiStepFormProps<T extends z.ZodType> {
|
||||
schema: T;
|
||||
@@ -287,7 +287,7 @@ export function useMultiStepForm<Schema extends z.ZodType>(
|
||||
const mutation = useMutation({
|
||||
mutationFn: () => {
|
||||
return form.handleSubmit(onSubmit)();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return useMemo(
|
||||
|
||||
@@ -165,7 +165,7 @@ function getClassNameBuilder() {
|
||||
selected: false,
|
||||
complete: false,
|
||||
className: 'bg-muted',
|
||||
}
|
||||
},
|
||||
],
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
|
||||
Reference in New Issue
Block a user