diff --git a/apps/start/src/routes/_login.login.tsx b/apps/start/src/routes/_login.login.tsx index ef36777ed..89c7c7e0b 100644 --- a/apps/start/src/routes/_login.login.tsx +++ b/apps/start/src/routes/_login.login.tsx @@ -9,6 +9,11 @@ import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { useCookieStore } from '@/hooks/use-cookie-store'; import { createTitle, PAGE_TITLES } from '@/utils/title'; +const validateSearch = z.object({ + error: z.string().optional(), + correlationId: z.string().optional(), + inviteId: z.string().optional(), +}); export const Route = createFileRoute('/_login/login')({ component: LoginPage, head: () => ({ @@ -17,15 +22,20 @@ export const Route = createFileRoute('/_login/login')({ { name: 'robots', content: 'noindex, follow' }, ], }), - validateSearch: z.object({ - error: z.string().optional(), - correlationId: z.string().optional(), - inviteId: z.string().optional(), - }), + validateSearch, + loader: ({ context, location }) => { + const search = validateSearch.safeParse(location.search); + return context.queryClient.ensureQueryData( + context.trpc.auth.isRegistrationAllowed.queryOptions({ + inviteId: search.success ? search.data.inviteId : undefined, + }) + ); + }, }); function LoginPage() { const { error, correlationId, inviteId } = Route.useSearch(); + const isRegistrationAllowed = Route.useLoaderData(); const [lastProvider] = useCookieStore( 'last-auth-provider', null @@ -35,15 +45,21 @@ function LoginPage() {

Sign in

-

- Don't have an account?{' '} - - Create one today - -

+ {isRegistrationAllowed && ( +

+ Don't have an account?{' '} + + Create one today + +

+ )}
{error && ( +
+

+ {inviteId + ? 'Registration is unavailable' + : 'Registration is disabled'} +

+

+ {inviteId + ? 'This invitation no longer exists, has already been used, or invitations are disabled on this instance. Ask an administrator for help.' + : "New accounts can't be created on this instance. Ask an administrator to invite you."} +

+

+ Already have an account?{' '} + + Sign in + +

+
+
+ ); + } + return (
diff --git a/packages/trpc/src/routers/auth.ts b/packages/trpc/src/routers/auth.ts index 5f7dec314..bd6252b87 100644 --- a/packages/trpc/src/routers/auth.ts +++ b/packages/trpc/src/routers/auth.ts @@ -589,6 +589,11 @@ export const authRouter = createTRPCRouter({ return ctx.session; }), + // Lets the login/onboarding pages hide sign-up when it would be rejected. + isRegistrationAllowed: publicProcedure + .input(z.object({ inviteId: z.string().nullish() })) + .query(({ input }) => getIsRegistrationAllowed(input.inviteId)), + extendSession: publicProcedure.mutation(async ({ ctx }) => { if (!(ctx.session.session && ctx.cookies.session)) { return { extended: false };