mirror of
https://github.com/documenso/documenso.git
synced 2025-11-19 11:12:06 +10:00
fix: wip
This commit is contained in:
@ -13,6 +13,7 @@ import {
|
|||||||
useLocation,
|
useLocation,
|
||||||
} from 'react-router';
|
} from 'react-router';
|
||||||
import { ThemeProvider } from 'remix-themes';
|
import { ThemeProvider } from 'remix-themes';
|
||||||
|
import { getOptionalLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { SessionProvider } from '@documenso/lib/client-only/providers/session';
|
import { SessionProvider } from '@documenso/lib/client-only/providers/session';
|
||||||
import { APP_I18N_OPTIONS, type SupportedLanguageCodes } from '@documenso/lib/constants/i18n';
|
import { APP_I18N_OPTIONS, type SupportedLanguageCodes } from '@documenso/lib/constants/i18n';
|
||||||
@ -82,7 +83,9 @@ export const links: Route.LinksFunction = () => [
|
|||||||
// };
|
// };
|
||||||
// }
|
// }
|
||||||
|
|
||||||
export async function loader({ request, context }: Route.LoaderArgs) {
|
export async function loader({ request }: Route.LoaderArgs) {
|
||||||
|
const session = getOptionalLoaderSession();
|
||||||
|
|
||||||
const { getTheme } = await themeSessionResolver(request);
|
const { getTheme } = await themeSessionResolver(request);
|
||||||
|
|
||||||
let lang: SupportedLanguageCodes = await langCookie.parse(request.headers.get('cookie') ?? '');
|
let lang: SupportedLanguageCodes = await langCookie.parse(request.headers.get('cookie') ?? '');
|
||||||
@ -95,7 +98,7 @@ export async function loader({ request, context }: Route.LoaderArgs) {
|
|||||||
{
|
{
|
||||||
lang,
|
lang,
|
||||||
theme: getTheme(),
|
theme: getTheme(),
|
||||||
session: context.session,
|
session,
|
||||||
__ENV__: Object.fromEntries(
|
__ENV__: Object.fromEntries(
|
||||||
Object.entries(process.env).filter(([key]) => key.startsWith('NEXT_')), // Todo: I'm pretty sure this will leak?
|
Object.entries(process.env).filter(([key]) => key.startsWith('NEXT_')), // Todo: I'm pretty sure this will leak?
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { Outlet, redirect } from 'react-router';
|
import { Outlet } from 'react-router';
|
||||||
|
import { getLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { getLimits } from '@documenso/ee/server-only/limits/client';
|
import { getLimits } from '@documenso/ee/server-only/limits/client';
|
||||||
import { LimitsProvider } from '@documenso/ee/server-only/limits/provider/client';
|
import { LimitsProvider } from '@documenso/ee/server-only/limits/provider/client';
|
||||||
@ -11,29 +12,25 @@ import { VerifyEmailBanner } from '~/components/general/verify-email-banner';
|
|||||||
|
|
||||||
import type { Route } from './+types/_layout';
|
import type { Route } from './+types/_layout';
|
||||||
|
|
||||||
export const loader = async ({ request, context }: Route.LoaderArgs) => {
|
export const loader = async ({ request }: Route.LoaderArgs) => {
|
||||||
const { session } = context;
|
const { user, teams, currentTeam } = getLoaderSession();
|
||||||
|
|
||||||
if (!session) {
|
|
||||||
throw redirect('/signin');
|
|
||||||
}
|
|
||||||
|
|
||||||
const requestHeaders = Object.fromEntries(request.headers.entries());
|
const requestHeaders = Object.fromEntries(request.headers.entries());
|
||||||
|
|
||||||
// Todo: Should only load this on first render.
|
// Todo: Should only load this on first render.
|
||||||
const [limits, banner] = await Promise.all([
|
const [limits, banner] = await Promise.all([
|
||||||
getLimits({ headers: requestHeaders, teamId: session.currentTeam?.id }),
|
getLimits({ headers: requestHeaders, teamId: currentTeam?.id }),
|
||||||
getSiteSettings().then((settings) =>
|
getSiteSettings().then((settings) =>
|
||||||
settings.find((setting) => setting.id === SITE_SETTINGS_BANNER_ID),
|
settings.find((setting) => setting.id === SITE_SETTINGS_BANNER_ID),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user: session.user,
|
user,
|
||||||
teams: session.teams,
|
teams,
|
||||||
banner,
|
banner,
|
||||||
limits,
|
limits,
|
||||||
teamId: session.currentTeam?.id,
|
teamId: currentTeam?.id,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +1,14 @@
|
|||||||
import { Trans } from '@lingui/macro';
|
import { Trans } from '@lingui/macro';
|
||||||
import { BarChart3, FileStack, Settings, Trophy, Users, Wallet2 } from 'lucide-react';
|
import { BarChart3, FileStack, Settings, Trophy, Users, Wallet2 } from 'lucide-react';
|
||||||
import { Link, Outlet, redirect, useLocation } from 'react-router';
|
import { Link, Outlet, redirect, useLocation } from 'react-router';
|
||||||
import { getRequiredLoaderSession } from 'server/utils/get-loader-session';
|
import { getLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { isAdmin } from '@documenso/lib/next-auth/guards/is-admin';
|
import { isAdmin } from '@documenso/lib/next-auth/guards/is-admin';
|
||||||
import { cn } from '@documenso/ui/lib/utils';
|
import { cn } from '@documenso/ui/lib/utils';
|
||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
|
|
||||||
import type { Route } from './+types/_layout';
|
export function loader() {
|
||||||
|
const { user } = getLoaderSession();
|
||||||
export function loader({ context }: Route.LoaderArgs) {
|
|
||||||
const { user } = getRequiredLoaderSession(context);
|
|
||||||
|
|
||||||
if (!user || !isAdmin(user)) {
|
if (!user || !isAdmin(user)) {
|
||||||
throw redirect('/documents');
|
throw redirect('/documents');
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { useLingui } from '@lingui/react';
|
|||||||
import { DocumentStatus, TeamMemberRole } from '@prisma/client';
|
import { DocumentStatus, TeamMemberRole } from '@prisma/client';
|
||||||
import { ChevronLeft, Clock9, Users2 } from 'lucide-react';
|
import { ChevronLeft, Clock9, Users2 } from 'lucide-react';
|
||||||
import { Link, redirect } from 'react-router';
|
import { Link, redirect } from 'react-router';
|
||||||
import { getRequiredLoaderSession } from 'server/utils/get-loader-session';
|
import { getLoaderSession } from 'server/utils/get-loader-session';
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import { useSession } from '@documenso/lib/client-only/providers/session';
|
import { useSession } from '@documenso/lib/client-only/providers/session';
|
||||||
@ -34,8 +34,8 @@ import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
|
|||||||
|
|
||||||
import type { Route } from './+types/$id._index';
|
import type { Route } from './+types/$id._index';
|
||||||
|
|
||||||
export async function loader({ params, context }: Route.LoaderArgs) {
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
const { user, currentTeam: team } = getRequiredLoaderSession(context);
|
const { user, currentTeam: team } = getLoaderSession();
|
||||||
|
|
||||||
const { id } = params;
|
const { id } = params;
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { Plural, Trans } from '@lingui/macro';
|
|||||||
import { DocumentStatus as InternalDocumentStatus, TeamMemberRole } from '@prisma/client';
|
import { DocumentStatus as InternalDocumentStatus, TeamMemberRole } from '@prisma/client';
|
||||||
import { ChevronLeft, Users2 } from 'lucide-react';
|
import { ChevronLeft, Users2 } from 'lucide-react';
|
||||||
import { Link, redirect } from 'react-router';
|
import { Link, redirect } from 'react-router';
|
||||||
import { getRequiredLoaderSession } from 'server/utils/get-loader-session';
|
import { getLoaderSession } from 'server/utils/get-loader-session';
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
|
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
|
||||||
@ -17,8 +17,8 @@ import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
|
|||||||
|
|
||||||
import type { Route } from './+types/$id.edit';
|
import type { Route } from './+types/$id.edit';
|
||||||
|
|
||||||
export async function loader({ params, context }: Route.LoaderArgs) {
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
const { user, currentTeam: team } = getRequiredLoaderSession(context);
|
const { user, currentTeam: team } = getLoaderSession();
|
||||||
|
|
||||||
const { id } = params;
|
const { id } = params;
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import type { Recipient } from '@prisma/client';
|
|||||||
import { ChevronLeft } from 'lucide-react';
|
import { ChevronLeft } from 'lucide-react';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { Link, redirect } from 'react-router';
|
import { Link, redirect } from 'react-router';
|
||||||
import { getRequiredLoaderSession } from 'server/utils/get-loader-session';
|
import { getLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id';
|
import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id';
|
||||||
import { getRecipientsForDocument } from '@documenso/lib/server-only/recipient/get-recipients-for-document';
|
import { getRecipientsForDocument } from '@documenso/lib/server-only/recipient/get-recipients-for-document';
|
||||||
@ -22,10 +22,10 @@ import { DocumentLogsTable } from '~/components/tables/document-logs-table';
|
|||||||
|
|
||||||
import type { Route } from './+types/$id.logs';
|
import type { Route } from './+types/$id.logs';
|
||||||
|
|
||||||
export async function loader({ params, context }: Route.LoaderArgs) {
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
const { id } = params;
|
const { id } = params;
|
||||||
|
|
||||||
const { user, currentTeam: team } = getRequiredLoaderSession(context);
|
const { user, currentTeam: team } = getLoaderSession();
|
||||||
|
|
||||||
const documentId = Number(id);
|
const documentId = Number(id);
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { Trans, msg } from '@lingui/macro';
|
|||||||
import { useLingui } from '@lingui/react';
|
import { useLingui } from '@lingui/react';
|
||||||
import type { TemplateDirectLink } from '@prisma/client';
|
import type { TemplateDirectLink } from '@prisma/client';
|
||||||
import { TemplateType } from '@prisma/client';
|
import { TemplateType } from '@prisma/client';
|
||||||
import { getRequiredLoaderSession } from 'server/utils/get-loader-session';
|
import { getLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { useSession } from '@documenso/lib/client-only/providers/session';
|
import { useSession } from '@documenso/lib/client-only/providers/session';
|
||||||
import { getUserPublicProfile } from '@documenso/lib/server-only/user/get-user-public-profile';
|
import { getUserPublicProfile } from '@documenso/lib/server-only/user/get-user-public-profile';
|
||||||
@ -43,8 +43,8 @@ const teamProfileText = {
|
|||||||
templatesSubtitle: msg`Show templates in your team public profile for your audience to sign and get started quickly`,
|
templatesSubtitle: msg`Show templates in your team public profile for your audience to sign and get started quickly`,
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function loader({ context }: Route.LoaderArgs) {
|
export async function loader() {
|
||||||
const { user } = getRequiredLoaderSession(context);
|
const { user } = getLoaderSession();
|
||||||
|
|
||||||
const { profile } = await getUserPublicProfile({
|
const { profile } = await getUserPublicProfile({
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import { redirect } from 'react-router';
|
import { redirect } from 'react-router';
|
||||||
|
import { getLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { formatDocumentsPath } from '@documenso/lib/utils/teams';
|
import { formatDocumentsPath } from '@documenso/lib/utils/teams';
|
||||||
|
|
||||||
import type { Route } from './+types/_index';
|
export function loader() {
|
||||||
|
const { currentTeam } = getLoaderSession();
|
||||||
export function loader({ context }: Route.LoaderArgs) {
|
if (!currentTeam) {
|
||||||
if (!context.session?.currentTeam) {
|
|
||||||
throw redirect('/documents');
|
throw redirect('/documents');
|
||||||
}
|
}
|
||||||
|
|
||||||
throw redirect(formatDocumentsPath(context.session.currentTeam.url));
|
throw redirect(formatDocumentsPath(currentTeam.url));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { Trans, msg } from '@lingui/macro';
|
|||||||
import { useLingui } from '@lingui/react';
|
import { useLingui } from '@lingui/react';
|
||||||
import { ChevronLeft } from 'lucide-react';
|
import { ChevronLeft } from 'lucide-react';
|
||||||
import { Link, Outlet, isRouteErrorResponse, redirect, useNavigate } from 'react-router';
|
import { Link, Outlet, isRouteErrorResponse, redirect, useNavigate } from 'react-router';
|
||||||
import { getRequiredLoaderSession } from 'server/utils/get-loader-session';
|
import { getLoaderSession } from 'server/utils/get-loader-session';
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import { AppErrorCode } from '@documenso/lib/errors/app-error';
|
import { AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||||
@ -14,8 +14,8 @@ import { TeamProvider } from '~/providers/team';
|
|||||||
|
|
||||||
import type { Route } from './+types/_layout';
|
import type { Route } from './+types/_layout';
|
||||||
|
|
||||||
export const loader = ({ context }: Route.LoaderArgs) => {
|
export const loader = () => {
|
||||||
const { currentTeam } = getRequiredLoaderSession(context);
|
const { currentTeam } = getLoaderSession();
|
||||||
|
|
||||||
if (!currentTeam) {
|
if (!currentTeam) {
|
||||||
throw redirect('/documents');
|
throw redirect('/documents');
|
||||||
|
|||||||
@ -1,16 +1,14 @@
|
|||||||
import { Trans } from '@lingui/macro';
|
import { Trans } from '@lingui/macro';
|
||||||
import { Outlet } from 'react-router';
|
import { Outlet } from 'react-router';
|
||||||
import { getRequiredLoaderTeamSession } from 'server/utils/get-loader-session';
|
import { getLoaderTeamSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { canExecuteTeamAction } from '@documenso/lib/utils/teams';
|
import { canExecuteTeamAction } from '@documenso/lib/utils/teams';
|
||||||
|
|
||||||
import { TeamSettingsNavDesktop } from '~/components/general/teams/team-settings-nav-desktop';
|
import { TeamSettingsNavDesktop } from '~/components/general/teams/team-settings-nav-desktop';
|
||||||
import { TeamSettingsNavMobile } from '~/components/general/teams/team-settings-nav-mobile';
|
import { TeamSettingsNavMobile } from '~/components/general/teams/team-settings-nav-mobile';
|
||||||
|
|
||||||
import type { Route } from '../+types/_layout';
|
export function loader() {
|
||||||
|
const { currentTeam: team } = getLoaderTeamSession();
|
||||||
export function loader({ context }: Route.LoaderArgs) {
|
|
||||||
const { currentTeam: team } = getRequiredLoaderTeamSession(context);
|
|
||||||
|
|
||||||
if (!team || !canExecuteTeamAction('MANAGE_TEAM', team.currentTeamMember.role)) {
|
if (!team || !canExecuteTeamAction('MANAGE_TEAM', team.currentTeamMember.role)) {
|
||||||
throw new Response(null, { status: 401 }); // Unauthorized.
|
throw new Response(null, { status: 401 }); // Unauthorized.
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Plural, Trans, msg } from '@lingui/macro';
|
import { Plural, Trans, msg } from '@lingui/macro';
|
||||||
import { useLingui } from '@lingui/react';
|
import { useLingui } from '@lingui/react';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { getRequiredLoaderTeamSession } from 'server/utils/get-loader-session';
|
import { getLoaderTeamSession } from 'server/utils/get-loader-session';
|
||||||
import type Stripe from 'stripe';
|
import type Stripe from 'stripe';
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
@ -15,8 +15,8 @@ import { TeamSettingsBillingInvoicesTable } from '~/components/tables/team-setti
|
|||||||
|
|
||||||
import type { Route } from './+types/billing';
|
import type { Route } from './+types/billing';
|
||||||
|
|
||||||
export async function loader({ context }: Route.LoaderArgs) {
|
export async function loader() {
|
||||||
const { currentTeam: team } = getRequiredLoaderTeamSession(context);
|
const { currentTeam: team } = getLoaderTeamSession();
|
||||||
|
|
||||||
let teamSubscription: Stripe.Subscription | null = null;
|
let teamSubscription: Stripe.Subscription | null = null;
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
import { getRequiredLoaderTeamSession } from 'server/utils/get-loader-session';
|
import { getLoaderTeamSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { getTeamPublicProfile } from '@documenso/lib/server-only/team/get-team-public-profile';
|
import { getTeamPublicProfile } from '@documenso/lib/server-only/team/get-team-public-profile';
|
||||||
|
|
||||||
import PublicProfilePage from '~/routes/_authenticated+/settings+/public-profile+/index';
|
import PublicProfilePage from '~/routes/_authenticated+/settings+/public-profile+/index';
|
||||||
|
|
||||||
import type { Route } from './+types/public-profile';
|
export async function loader() {
|
||||||
|
const { user, currentTeam: team } = getLoaderTeamSession();
|
||||||
export async function loader({ context }: Route.LoaderArgs) {
|
|
||||||
const { user, currentTeam: team } = getRequiredLoaderTeamSession(context);
|
|
||||||
|
|
||||||
const { profile } = await getTeamPublicProfile({
|
const { profile } = await getTeamPublicProfile({
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Trans } from '@lingui/macro';
|
import { Trans } from '@lingui/macro';
|
||||||
import { useLingui } from '@lingui/react';
|
import { useLingui } from '@lingui/react';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { getRequiredLoaderTeamSession } from 'server/utils/get-loader-session';
|
import { getLoaderTeamSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
||||||
import { getTeamTokens } from '@documenso/lib/server-only/public-api/get-all-team-tokens';
|
import { getTeamTokens } from '@documenso/lib/server-only/public-api/get-all-team-tokens';
|
||||||
@ -12,8 +12,8 @@ import { ApiTokenForm } from '~/components/forms/token';
|
|||||||
|
|
||||||
import type { Route } from './+types/tokens';
|
import type { Route } from './+types/tokens';
|
||||||
|
|
||||||
export async function loader({ context }: Route.LoaderArgs) {
|
export async function loader() {
|
||||||
const { user, currentTeam: team } = getRequiredLoaderTeamSession(context);
|
const { user, currentTeam: team } = getLoaderTeamSession();
|
||||||
|
|
||||||
const tokens = await getTeamTokens({ userId: user.id, teamId: team.id }).catch(() => null);
|
const tokens = await getTeamTokens({ userId: user.id, teamId: team.id }).catch(() => null);
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { Trans } from '@lingui/macro';
|
|||||||
import { DocumentSigningOrder, SigningStatus } from '@prisma/client';
|
import { DocumentSigningOrder, SigningStatus } from '@prisma/client';
|
||||||
import { ChevronLeft, LucideEdit } from 'lucide-react';
|
import { ChevronLeft, LucideEdit } from 'lucide-react';
|
||||||
import { Link, redirect, useNavigate } from 'react-router';
|
import { Link, redirect, useNavigate } from 'react-router';
|
||||||
import { getRequiredLoaderSession } from 'server/utils/get-loader-session';
|
import { getLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id';
|
import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id';
|
||||||
import { formatDocumentsPath, formatTemplatesPath } from '@documenso/lib/utils/teams';
|
import { formatDocumentsPath, formatTemplatesPath } from '@documenso/lib/utils/teams';
|
||||||
@ -24,8 +24,8 @@ import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
|
|||||||
|
|
||||||
import type { Route } from './+types/$id._index';
|
import type { Route } from './+types/$id._index';
|
||||||
|
|
||||||
export async function loader({ params, context }: Route.LoaderArgs) {
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
const { user, currentTeam: team } = getRequiredLoaderSession(context);
|
const { user, currentTeam: team } = getLoaderSession();
|
||||||
|
|
||||||
const { id } = params;
|
const { id } = params;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Trans } from '@lingui/macro';
|
import { Trans } from '@lingui/macro';
|
||||||
import { ChevronLeft } from 'lucide-react';
|
import { ChevronLeft } from 'lucide-react';
|
||||||
import { Link, redirect } from 'react-router';
|
import { Link, redirect } from 'react-router';
|
||||||
import { getRequiredLoaderSession } from 'server/utils/get-loader-session';
|
import { getLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
|
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
|
||||||
import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id';
|
import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id';
|
||||||
@ -15,8 +15,8 @@ import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
|
|||||||
import { TemplateDirectLinkDialogWrapper } from '../../../components/dialogs/template-direct-link-dialog-wrapper';
|
import { TemplateDirectLinkDialogWrapper } from '../../../components/dialogs/template-direct-link-dialog-wrapper';
|
||||||
import type { Route } from './+types/$id.edit';
|
import type { Route } from './+types/$id.edit';
|
||||||
|
|
||||||
export async function loader({ context, params }: Route.LoaderArgs) {
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
const { user, currentTeam: team } = getRequiredLoaderSession(context);
|
const { user, currentTeam: team } = getLoaderSession();
|
||||||
|
|
||||||
const { id } = params;
|
const { id } = params;
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import { redirect } from 'react-router';
|
import { redirect } from 'react-router';
|
||||||
|
import { getOptionalLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import type { Route } from './+types/_index';
|
export function loader() {
|
||||||
|
const session = getOptionalLoaderSession();
|
||||||
|
|
||||||
export function loader({ context }: Route.LoaderArgs) {
|
if (session) {
|
||||||
if (context.session) {
|
|
||||||
throw redirect('/documents');
|
throw redirect('/documents');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,24 +6,15 @@ import { ChevronLeft } from 'lucide-react';
|
|||||||
import { Link, Outlet } from 'react-router';
|
import { Link, Outlet } from 'react-router';
|
||||||
|
|
||||||
import LogoIcon from '@documenso/assets/logo_icon.png';
|
import LogoIcon from '@documenso/assets/logo_icon.png';
|
||||||
|
import { useSession } from '@documenso/lib/client-only/providers/session';
|
||||||
import { cn } from '@documenso/ui/lib/utils';
|
import { cn } from '@documenso/ui/lib/utils';
|
||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
|
|
||||||
import { Header as AuthenticatedHeader } from '~/components/general/app-header';
|
import { Header as AuthenticatedHeader } from '~/components/general/app-header';
|
||||||
import { Logo } from '~/components/general/branding-logo';
|
import { BrandingLogo } from '~/components/general/branding-logo';
|
||||||
|
|
||||||
import type { Route } from './+types/_layout';
|
export default function PublicProfileLayout() {
|
||||||
|
const session = useSession();
|
||||||
export function loader({ context }: Route.LoaderArgs) {
|
|
||||||
const { session } = context;
|
|
||||||
|
|
||||||
return {
|
|
||||||
session,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function PublicProfileLayout({ loaderData }: Route.ComponentProps) {
|
|
||||||
const { session } = loaderData;
|
|
||||||
|
|
||||||
const [scrollY, setScrollY] = useState(0);
|
const [scrollY, setScrollY] = useState(0);
|
||||||
|
|
||||||
@ -53,7 +44,7 @@ export default function PublicProfileLayout({ loaderData }: Route.ComponentProps
|
|||||||
to="/"
|
to="/"
|
||||||
className="focus-visible:ring-ring ring-offset-background rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 md:inline"
|
className="focus-visible:ring-ring ring-offset-background rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 md:inline"
|
||||||
>
|
>
|
||||||
<Logo className="hidden h-6 w-auto sm:block" />
|
<BrandingLogo className="hidden h-6 w-auto sm:block" />
|
||||||
|
|
||||||
<img
|
<img
|
||||||
src={LogoIcon}
|
src={LogoIcon}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { Trans } from '@lingui/macro';
|
import { Trans } from '@lingui/macro';
|
||||||
import { ChevronLeft } from 'lucide-react';
|
import { ChevronLeft } from 'lucide-react';
|
||||||
import { Link, Outlet } from 'react-router';
|
import { Link, Outlet } from 'react-router';
|
||||||
|
import { getOptionalLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
|
|
||||||
@ -8,10 +9,12 @@ import { Header as AuthenticatedHeader } from '~/components/general/app-header';
|
|||||||
|
|
||||||
import type { Route } from './+types/_layout';
|
import type { Route } from './+types/_layout';
|
||||||
|
|
||||||
export function loader({ context }: Route.LoaderArgs) {
|
export function loader() {
|
||||||
|
const session = getOptionalLoaderSession();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user: context.session?.user,
|
user: session?.user,
|
||||||
teams: context.session?.teams || [],
|
teams: session?.teams || [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { Plural } from '@lingui/macro';
|
import { Plural } from '@lingui/macro';
|
||||||
import { UsersIcon } from 'lucide-react';
|
import { UsersIcon } from 'lucide-react';
|
||||||
import { redirect } from 'react-router';
|
import { redirect } from 'react-router';
|
||||||
|
import { getOptionalLoaderSession } from 'server/utils/get-loader-session';
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import { useOptionalSession } from '@documenso/lib/client-only/providers/session';
|
import { useOptionalSession } from '@documenso/lib/client-only/providers/session';
|
||||||
@ -16,7 +17,9 @@ import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
|
|||||||
|
|
||||||
import type { Route } from './+types/_index';
|
import type { Route } from './+types/_index';
|
||||||
|
|
||||||
export async function loader({ params, context }: Route.LoaderArgs) {
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
|
const session = getOptionalLoaderSession();
|
||||||
|
|
||||||
const { token } = params;
|
const { token } = params;
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
@ -45,7 +48,7 @@ export async function loader({ params, context }: Route.LoaderArgs) {
|
|||||||
|
|
||||||
// Ensure typesafety when we add more options.
|
// Ensure typesafety when we add more options.
|
||||||
const isAccessAuthValid = match(derivedRecipientAccessAuth)
|
const isAccessAuthValid = match(derivedRecipientAccessAuth)
|
||||||
.with(DocumentAccessAuth.ACCOUNT, () => context.session?.user !== null)
|
.with(DocumentAccessAuth.ACCOUNT, () => session?.user !== null)
|
||||||
.with(null, () => true)
|
.with(null, () => true)
|
||||||
.exhaustive();
|
.exhaustive();
|
||||||
|
|
||||||
@ -67,6 +70,7 @@ export default function DirectTemplatePage() {
|
|||||||
|
|
||||||
const data = useSuperLoaderData<typeof loader>();
|
const data = useSuperLoaderData<typeof loader>();
|
||||||
|
|
||||||
|
// Should not be possible for directLink to be null.
|
||||||
if (!data.isAccessAuthValid) {
|
if (!data.isAccessAuthValid) {
|
||||||
return <DirectTemplateAuthPageView />;
|
return <DirectTemplateAuthPageView />;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro';
|
|||||||
import { DocumentStatus, SigningStatus } from '@prisma/client';
|
import { DocumentStatus, SigningStatus } from '@prisma/client';
|
||||||
import { Clock8 } from 'lucide-react';
|
import { Clock8 } from 'lucide-react';
|
||||||
import { Link, redirect } from 'react-router';
|
import { Link, redirect } from 'react-router';
|
||||||
|
import { getOptionalLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import signingCelebration from '@documenso/assets/images/signing-celebration.png';
|
import signingCelebration from '@documenso/assets/images/signing-celebration.png';
|
||||||
import { useOptionalSession } from '@documenso/lib/client-only/providers/session';
|
import { useOptionalSession } from '@documenso/lib/client-only/providers/session';
|
||||||
@ -25,14 +26,16 @@ import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
|
|||||||
|
|
||||||
import type { Route } from './+types/_index';
|
import type { Route } from './+types/_index';
|
||||||
|
|
||||||
export async function loader({ params, context }: Route.LoaderArgs) {
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
|
const session = getOptionalLoaderSession();
|
||||||
|
|
||||||
const { token } = params;
|
const { token } = params;
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
throw new Response('Not Found', { status: 404 });
|
throw new Response('Not Found', { status: 404 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = context.session?.user;
|
const user = session?.user;
|
||||||
|
|
||||||
const [document, fields, recipient, completedFields] = await Promise.all([
|
const [document, fields, recipient, completedFields] = await Promise.all([
|
||||||
getDocumentAndSenderByToken({
|
getDocumentAndSenderByToken({
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { useLingui } from '@lingui/react';
|
|||||||
import { DocumentStatus, FieldType, RecipientRole } from '@prisma/client';
|
import { DocumentStatus, FieldType, RecipientRole } from '@prisma/client';
|
||||||
import { CheckCircle2, Clock8, FileSearch } from 'lucide-react';
|
import { CheckCircle2, Clock8, FileSearch } from 'lucide-react';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
import { getOptionalLoaderSession } from 'server/utils/get-loader-session';
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import signingCelebration from '@documenso/assets/images/signing-celebration.png';
|
import signingCelebration from '@documenso/assets/images/signing-celebration.png';
|
||||||
@ -27,14 +28,16 @@ import { DocumentSigningAuthPageView } from '~/components/general/document-signi
|
|||||||
|
|
||||||
import type { Route } from './+types/complete';
|
import type { Route } from './+types/complete';
|
||||||
|
|
||||||
export async function loader({ params, context }: Route.LoaderArgs) {
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
|
const session = getOptionalLoaderSession();
|
||||||
|
|
||||||
const { token } = params;
|
const { token } = params;
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
throw new Response('Not Found', { status: 404 });
|
throw new Response('Not Found', { status: 404 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = context.session?.user;
|
const user = session?.user;
|
||||||
|
|
||||||
const document = await getDocumentAndSenderByToken({
|
const document = await getDocumentAndSenderByToken({
|
||||||
token,
|
token,
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro';
|
|||||||
import { FieldType } from '@prisma/client';
|
import { FieldType } from '@prisma/client';
|
||||||
import { XCircle } from 'lucide-react';
|
import { XCircle } from 'lucide-react';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
import { getOptionalLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { useOptionalSession } from '@documenso/lib/client-only/providers/session';
|
import { useOptionalSession } from '@documenso/lib/client-only/providers/session';
|
||||||
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
|
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
|
||||||
@ -16,14 +17,16 @@ import { truncateTitle } from '~/utils/truncate-title';
|
|||||||
|
|
||||||
import type { Route } from './+types/rejected';
|
import type { Route } from './+types/rejected';
|
||||||
|
|
||||||
export async function loader({ params, context }: Route.LoaderArgs) {
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
|
const session = getOptionalLoaderSession();
|
||||||
|
|
||||||
const { token } = params;
|
const { token } = params;
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
throw new Response('Not Found', { status: 404 });
|
throw new Response('Not Found', { status: 404 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = context.session?.user;
|
const user = session?.user;
|
||||||
|
|
||||||
const document = await getDocumentAndSenderByToken({
|
const document = await getDocumentAndSenderByToken({
|
||||||
token,
|
token,
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro';
|
|||||||
import type { Team } from '@prisma/client';
|
import type { Team } from '@prisma/client';
|
||||||
import { DocumentStatus } from '@prisma/client';
|
import { DocumentStatus } from '@prisma/client';
|
||||||
import { Link, redirect } from 'react-router';
|
import { Link, redirect } from 'react-router';
|
||||||
|
import { getOptionalLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id';
|
import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id';
|
||||||
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
|
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
|
||||||
@ -12,7 +13,9 @@ import { Button } from '@documenso/ui/primitives/button';
|
|||||||
|
|
||||||
import type { Route } from './+types/waiting';
|
import type { Route } from './+types/waiting';
|
||||||
|
|
||||||
export async function loader({ params, context }: Route.LoaderArgs) {
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
|
const session = getOptionalLoaderSession();
|
||||||
|
|
||||||
const { token } = params;
|
const { token } = params;
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
@ -34,7 +37,7 @@ export async function loader({ params, context }: Route.LoaderArgs) {
|
|||||||
|
|
||||||
let isOwnerOrTeamMember = false;
|
let isOwnerOrTeamMember = false;
|
||||||
|
|
||||||
const user = context.session?.user;
|
const user = session?.user;
|
||||||
let team: Team | null = null;
|
let team: Team | null = null;
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { Trans } from '@lingui/macro';
|
import { Trans } from '@lingui/macro';
|
||||||
import { Link, redirect } from 'react-router';
|
import { Link, redirect } from 'react-router';
|
||||||
|
import { getOptionalLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
IS_GOOGLE_SSO_ENABLED,
|
IS_GOOGLE_SSO_ENABLED,
|
||||||
@ -10,14 +11,14 @@ import { env } from '@documenso/lib/utils/env';
|
|||||||
|
|
||||||
import { SignInForm } from '~/components/forms/signin';
|
import { SignInForm } from '~/components/forms/signin';
|
||||||
|
|
||||||
import type { Route } from './+types/signin';
|
|
||||||
|
|
||||||
export function meta() {
|
export function meta() {
|
||||||
return [{ title: 'Sign In' }];
|
return [{ title: 'Sign In' }];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loader({ context }: Route.LoaderArgs) {
|
export function loader() {
|
||||||
if (context.session) {
|
const session = getOptionalLoaderSession();
|
||||||
|
|
||||||
|
if (session) {
|
||||||
throw redirect('/documents');
|
throw redirect('/documents');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro';
|
|||||||
import { TeamMemberInviteStatus } from '@prisma/client';
|
import { TeamMemberInviteStatus } from '@prisma/client';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
import { getOptionalLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { encryptSecondaryData } from '@documenso/lib/server-only/crypto/encrypt';
|
import { encryptSecondaryData } from '@documenso/lib/server-only/crypto/encrypt';
|
||||||
import { declineTeamInvitation } from '@documenso/lib/server-only/team/decline-team-invitation';
|
import { declineTeamInvitation } from '@documenso/lib/server-only/team/decline-team-invitation';
|
||||||
@ -11,7 +12,9 @@ import { Button } from '@documenso/ui/primitives/button';
|
|||||||
|
|
||||||
import type { Route } from './+types/team.decline.$token';
|
import type { Route } from './+types/team.decline.$token';
|
||||||
|
|
||||||
export async function loader({ params, context }: Route.LoaderArgs) {
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
|
const session = getOptionalLoaderSession();
|
||||||
|
|
||||||
const { token } = params;
|
const { token } = params;
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
@ -71,7 +74,7 @@ export async function loader({ params, context }: Route.LoaderArgs) {
|
|||||||
} as const;
|
} as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isSessionUserTheInvitedUser = user.id === context.session?.user.id;
|
const isSessionUserTheInvitedUser = user.id === session?.user.id;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
state: 'Success',
|
state: 'Success',
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro';
|
|||||||
import { TeamMemberInviteStatus } from '@prisma/client';
|
import { TeamMemberInviteStatus } from '@prisma/client';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
import { getOptionalLoaderSession } from 'server/utils/get-loader-session';
|
||||||
|
|
||||||
import { encryptSecondaryData } from '@documenso/lib/server-only/crypto/encrypt';
|
import { encryptSecondaryData } from '@documenso/lib/server-only/crypto/encrypt';
|
||||||
import { acceptTeamInvitation } from '@documenso/lib/server-only/team/accept-team-invitation';
|
import { acceptTeamInvitation } from '@documenso/lib/server-only/team/accept-team-invitation';
|
||||||
@ -11,7 +12,9 @@ import { Button } from '@documenso/ui/primitives/button';
|
|||||||
|
|
||||||
import type { Route } from './+types/team.invite.$token';
|
import type { Route } from './+types/team.invite.$token';
|
||||||
|
|
||||||
export async function loader({ params, context }: Route.LoaderArgs) {
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
|
const session = getOptionalLoaderSession();
|
||||||
|
|
||||||
const { token } = params;
|
const { token } = params;
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
@ -74,7 +77,7 @@ export async function loader({ params, context }: Route.LoaderArgs) {
|
|||||||
} as const;
|
} as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isSessionUserTheInvitedUser = user.id === context.session?.user.id;
|
const isSessionUserTheInvitedUser = user.id === session?.user.id;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
state: 'Success',
|
state: 'Success',
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { data } from 'react-router';
|
import { data } from 'react-router';
|
||||||
import { getRequiredLoaderSession } from 'server/utils/get-loader-session';
|
import { getLoaderSession } from 'server/utils/get-loader-session';
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
|
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
|
||||||
@ -17,7 +17,7 @@ import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
|
|||||||
|
|
||||||
import type { Route } from './+types/direct.$url';
|
import type { Route } from './+types/direct.$url';
|
||||||
|
|
||||||
export async function loader({ params, context }: Route.LoaderArgs) {
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
if (!params.url) {
|
if (!params.url) {
|
||||||
throw new Response('Not found', { status: 404 });
|
throw new Response('Not found', { status: 404 });
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ export async function loader({ params, context }: Route.LoaderArgs) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = getRequiredLoaderSession(context);
|
const { user } = getLoaderSession();
|
||||||
|
|
||||||
const { derivedRecipientAccessAuth } = extractDocumentAuthMethods({
|
const { derivedRecipientAccessAuth } = extractDocumentAuthMethods({
|
||||||
documentAuth: template.authOptions,
|
documentAuth: template.authOptions,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { DocumentStatus } from '@prisma/client';
|
import { DocumentStatus } from '@prisma/client';
|
||||||
import { data } from 'react-router';
|
import { data } from 'react-router';
|
||||||
import { getRequiredLoaderSession } from 'server/utils/get-loader-session';
|
import { getLoaderSession } from 'server/utils/get-loader-session';
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
|
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
|
||||||
@ -20,14 +20,14 @@ import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
|
|||||||
|
|
||||||
import type { Route } from './+types/sign.$url';
|
import type { Route } from './+types/sign.$url';
|
||||||
|
|
||||||
export async function loader({ params, context }: Route.LoaderArgs) {
|
export async function loader({ params }: Route.LoaderArgs) {
|
||||||
if (!params.url) {
|
if (!params.url) {
|
||||||
throw new Response('Not found', { status: 404 });
|
throw new Response('Not found', { status: 404 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = params.url;
|
const token = params.url;
|
||||||
|
|
||||||
const { user } = getRequiredLoaderSession(context);
|
const { user } = getLoaderSession();
|
||||||
|
|
||||||
const [document, fields, recipient] = await Promise.all([
|
const [document, fields, recipient] = await Promise.all([
|
||||||
getDocumentAndSenderByToken({
|
getDocumentAndSenderByToken({
|
||||||
|
|||||||
@ -1,24 +1,27 @@
|
|||||||
|
import type { Context, Next } from 'hono';
|
||||||
|
|
||||||
import { extractSessionCookieFromHeaders } from '@documenso/auth/server/lib/session/session-cookies';
|
import { extractSessionCookieFromHeaders } from '@documenso/auth/server/lib/session/session-cookies';
|
||||||
import { getSession } from '@documenso/auth/server/lib/utils/get-session';
|
import { getSession } from '@documenso/auth/server/lib/utils/get-session';
|
||||||
|
import type { AppSession } from '@documenso/lib/client-only/providers/session';
|
||||||
import { type TGetTeamByUrlResponse, getTeamByUrl } from '@documenso/lib/server-only/team/get-team';
|
import { type TGetTeamByUrlResponse, getTeamByUrl } from '@documenso/lib/server-only/team/get-team';
|
||||||
import { type TGetTeamsResponse, getTeams } from '@documenso/lib/server-only/team/get-teams';
|
import { type TGetTeamsResponse, getTeams } from '@documenso/lib/server-only/team/get-teams';
|
||||||
import { extractRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
import {
|
||||||
|
type RequestMetadata,
|
||||||
|
extractRequestMetadata,
|
||||||
|
} from '@documenso/lib/universal/extract-request-metadata';
|
||||||
import { AppLogger } from '@documenso/lib/utils/debugger';
|
import { AppLogger } from '@documenso/lib/utils/debugger';
|
||||||
|
|
||||||
type GetLoadContextArgs = {
|
const logger = new AppLogger('Middleware');
|
||||||
request: Request;
|
|
||||||
|
export type AppContext = {
|
||||||
|
requestMetadata: RequestMetadata;
|
||||||
|
session: AppSession | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
declare module 'react-router' {
|
export const appContext = async (c: Context, next: Next) => {
|
||||||
interface AppLoadContext extends Awaited<ReturnType<typeof getLoadContext>> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
const logger = new AppLogger('Context');
|
|
||||||
|
|
||||||
export async function getLoadContext(args: GetLoadContextArgs) {
|
|
||||||
const initTime = Date.now();
|
const initTime = Date.now();
|
||||||
|
|
||||||
const request = args.request;
|
const request = c.req.raw;
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
|
|
||||||
const noSessionCookie = extractSessionCookieFromHeaders(request.headers) === null;
|
const noSessionCookie = extractSessionCookieFromHeaders(request.headers) === null;
|
||||||
@ -26,10 +29,12 @@ export async function getLoadContext(args: GetLoadContextArgs) {
|
|||||||
if (!isPageRequest(request) || noSessionCookie || blacklistedPathsRegex.test(url.pathname)) {
|
if (!isPageRequest(request) || noSessionCookie || blacklistedPathsRegex.test(url.pathname)) {
|
||||||
logger.log('Pathname ignored', url.pathname);
|
logger.log('Pathname ignored', url.pathname);
|
||||||
|
|
||||||
return {
|
setAppContext(c, {
|
||||||
requestMetadata: extractRequestMetadata(request),
|
requestMetadata: extractRequestMetadata(request),
|
||||||
session: null,
|
session: null,
|
||||||
};
|
});
|
||||||
|
|
||||||
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
const splitUrl = url.pathname.replace('.data', '').split('/');
|
const splitUrl = url.pathname.replace('.data', '').split('/');
|
||||||
@ -37,7 +42,7 @@ export async function getLoadContext(args: GetLoadContextArgs) {
|
|||||||
let team: TGetTeamByUrlResponse | null = null;
|
let team: TGetTeamByUrlResponse | null = null;
|
||||||
let teams: TGetTeamsResponse = [];
|
let teams: TGetTeamsResponse = [];
|
||||||
|
|
||||||
const session = await getSession(args.request);
|
const session = await getSession(c);
|
||||||
|
|
||||||
if (session.isAuthenticated) {
|
if (session.isAuthenticated) {
|
||||||
let teamUrl = null;
|
let teamUrl = null;
|
||||||
@ -58,7 +63,7 @@ export async function getLoadContext(args: GetLoadContextArgs) {
|
|||||||
const endTime = Date.now();
|
const endTime = Date.now();
|
||||||
logger.log(`Pathname accepted in ${endTime - initTime}ms`, url.pathname);
|
logger.log(`Pathname accepted in ${endTime - initTime}ms`, url.pathname);
|
||||||
|
|
||||||
return {
|
setAppContext(c, {
|
||||||
requestMetadata: extractRequestMetadata(request),
|
requestMetadata: extractRequestMetadata(request),
|
||||||
session: session.isAuthenticated
|
session: session.isAuthenticated
|
||||||
? {
|
? {
|
||||||
@ -68,8 +73,14 @@ export async function getLoadContext(args: GetLoadContextArgs) {
|
|||||||
teams,
|
teams,
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
};
|
});
|
||||||
}
|
|
||||||
|
return next();
|
||||||
|
};
|
||||||
|
|
||||||
|
const setAppContext = (c: Context, context: AppContext) => {
|
||||||
|
c.set('context', context);
|
||||||
|
};
|
||||||
|
|
||||||
const isPageRequest = (request: Request) => {
|
const isPageRequest = (request: Request) => {
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
@ -1,4 +1,5 @@
|
|||||||
import { Hono } from 'hono';
|
import { Hono } from 'hono';
|
||||||
|
import { contextStorage } from 'hono/context-storage';
|
||||||
import { PDFDocument } from 'pdf-lib';
|
import { PDFDocument } from 'pdf-lib';
|
||||||
|
|
||||||
import { tsRestHonoApp } from '@documenso/api/hono';
|
import { tsRestHonoApp } from '@documenso/api/hono';
|
||||||
@ -11,10 +12,21 @@ import { putFile } from '@documenso/lib/universal/upload/put-file';
|
|||||||
import { getPresignGetUrl } from '@documenso/lib/universal/upload/server-actions';
|
import { getPresignGetUrl } from '@documenso/lib/universal/upload/server-actions';
|
||||||
import { openApiDocument } from '@documenso/trpc/server/open-api';
|
import { openApiDocument } from '@documenso/trpc/server/open-api';
|
||||||
|
|
||||||
|
import { type AppContext, appContext } from './context';
|
||||||
import { openApiTrpcServerHandler } from './trpc/hono-trpc-open-api';
|
import { openApiTrpcServerHandler } from './trpc/hono-trpc-open-api';
|
||||||
import { reactRouterTrpcServer } from './trpc/hono-trpc-remix';
|
import { reactRouterTrpcServer } from './trpc/hono-trpc-remix';
|
||||||
|
|
||||||
const app = new Hono();
|
export interface HonoEnv {
|
||||||
|
Variables: {
|
||||||
|
context: AppContext;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = new Hono<HonoEnv>();
|
||||||
|
|
||||||
|
app.use(contextStorage());
|
||||||
|
|
||||||
|
app.use(appContext);
|
||||||
|
|
||||||
// App middleware.
|
// App middleware.
|
||||||
// app.use('*', appMiddleware);
|
// app.use('*', appMiddleware);
|
||||||
|
|||||||
@ -12,6 +12,7 @@ export const openApiTrpcServerHandler = async (c: Context) => {
|
|||||||
endpoint: API_V2_BETA_URL,
|
endpoint: API_V2_BETA_URL,
|
||||||
router: appRouter,
|
router: appRouter,
|
||||||
// Todo: Test this, since it's not using the createContext params.
|
// Todo: Test this, since it's not using the createContext params.
|
||||||
|
// Todo: Reduce calls since we fetch on most request? maybe
|
||||||
createContext: async () => createTrpcContext({ c, requestSource: 'apiV2' }),
|
createContext: async () => createTrpcContext({ c, requestSource: 'apiV2' }),
|
||||||
req: c.req.raw,
|
req: c.req.raw,
|
||||||
onError: (opts) => handleTrpcRouterError(opts, 'apiV2'),
|
onError: (opts) => handleTrpcRouterError(opts, 'apiV2'),
|
||||||
|
|||||||
@ -1,31 +1,43 @@
|
|||||||
import type { AppLoadContext } from 'react-router';
|
import { getContext } from 'hono/context-storage';
|
||||||
import { redirect } from 'react-router';
|
import { redirect } from 'react-router';
|
||||||
|
import type { HonoEnv } from 'server';
|
||||||
|
|
||||||
|
import type { AppSession } from '@documenso/lib/client-only/providers/session';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the session context or throws a redirect to signin if it is not present.
|
* Returns the session context or throws a redirect to signin if it is not present.
|
||||||
*/
|
*/
|
||||||
export const getRequiredLoaderSession = (context: AppLoadContext) => {
|
export const getLoaderSession = (): AppSession => {
|
||||||
if (!context.session) {
|
const session = getOptionalLoaderSession();
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
throw redirect('/signin'); // Todo: Maybe add a redirect cookie to come back?
|
throw redirect('/signin'); // Todo: Maybe add a redirect cookie to come back?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return session;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getOptionalLoaderSession = (): AppSession | null => {
|
||||||
|
const { context } = getContext<HonoEnv>().var;
|
||||||
return context.session;
|
return context.session;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the team session context or throws a redirect to signin if it is not present.
|
* Returns the team session context or throws a redirect to signin if it is not present.
|
||||||
*/
|
*/
|
||||||
export const getRequiredLoaderTeamSession = (context: AppLoadContext) => {
|
export const getLoaderTeamSession = () => {
|
||||||
if (!context.session) {
|
const session = getOptionalLoaderSession();
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
throw redirect('/signin'); // Todo: Maybe add a redirect cookie to come back?
|
throw redirect('/signin'); // Todo: Maybe add a redirect cookie to come back?
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.session.currentTeam) {
|
if (!session.currentTeam) {
|
||||||
throw new Response(null, { status: 404 }); // Todo: Test that 404 page shows up.
|
throw new Response(null, { status: 404 }); // Todo: Test that 404 page shows up.
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...context.session,
|
...session,
|
||||||
currentTeam: context.session.currentTeam,
|
currentTeam: session.currentTeam,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,8 +8,6 @@ import { defineConfig, loadEnv } from 'vite';
|
|||||||
import macrosPlugin from 'vite-plugin-babel-macros';
|
import macrosPlugin from 'vite-plugin-babel-macros';
|
||||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||||
|
|
||||||
import { getLoadContext } from './server/load-context';
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
envDir: path.join(__dirname, '../../'),
|
envDir: path.join(__dirname, '../../'),
|
||||||
envPrefix: '__DO_NOT_USE_OR_YOU_WILL_BE_FIRED__',
|
envPrefix: '__DO_NOT_USE_OR_YOU_WILL_BE_FIRED__',
|
||||||
@ -54,7 +52,6 @@ export default defineConfig({
|
|||||||
lingui(),
|
lingui(),
|
||||||
macrosPlugin(),
|
macrosPlugin(),
|
||||||
serverAdapter({
|
serverAdapter({
|
||||||
getLoadContext,
|
|
||||||
entry: 'server/index.ts',
|
entry: 'server/index.ts',
|
||||||
}),
|
}),
|
||||||
tsconfigPaths(),
|
tsconfigPaths(),
|
||||||
|
|||||||
@ -1,25 +1,30 @@
|
|||||||
import { createContext, useContext } from 'react';
|
import { createContext, useContext } from 'react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import type { Session, User } from '@prisma/client';
|
import type { Session, User } from '@documenso/prisma/client';
|
||||||
|
|
||||||
interface AuthProviderProps {
|
import type { TGetTeamByUrlResponse } from '../../server-only/team/get-team';
|
||||||
children: React.ReactNode;
|
import type { TGetTeamsResponse } from '../../server-only/team/get-teams';
|
||||||
session: DocumensoSession | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type DocumensoSession = {
|
export type AppSession = {
|
||||||
user: User; // Todo: Exclude password
|
|
||||||
session: Session;
|
session: Session;
|
||||||
|
user: User; // Todo: Remove password, and redundant fields.
|
||||||
|
currentTeam: TGetTeamByUrlResponse | null;
|
||||||
|
teams: TGetTeamsResponse;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SessionContext = createContext<DocumensoSession | null>(null);
|
interface SessionProviderProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
session: AppSession | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SessionContext = createContext<AppSession | null>(null);
|
||||||
|
|
||||||
export const useSession = () => {
|
export const useSession = () => {
|
||||||
const context = useContext(SessionContext);
|
const context = useContext(SessionContext);
|
||||||
|
|
||||||
if (!context) {
|
if (!context) {
|
||||||
throw new Error('useAuth must be used within a AuthProvider');
|
throw new Error('useSession must be used within a SessionProvider');
|
||||||
}
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
@ -34,6 +39,6 @@ export const useOptionalSession = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SessionProvider = ({ children, session }: AuthProviderProps) => {
|
export const SessionProvider = ({ children, session }: SessionProviderProps) => {
|
||||||
return <SessionContext.Provider value={session}>{children}</SessionContext.Provider>;
|
return <SessionContext.Provider value={session}>{children}</SessionContext.Provider>;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user