This commit is contained in:
David Nguyen
2025-01-31 23:17:50 +11:00
parent aec44b78d0
commit e20cb7e179
79 changed files with 3613 additions and 300 deletions

View File

@ -2,13 +2,11 @@ import type { MessageDescriptor } from '@lingui/core';
import { Trans, msg } from '@lingui/macro';
import { useLingui } from '@lingui/react';
import { ChevronLeft } from 'lucide-react';
import { Link, Outlet, isRouteErrorResponse, replace, useNavigate } from 'react-router';
import { Link, Outlet, isRouteErrorResponse, redirect, useNavigate } from 'react-router';
import { getRequiredSessionContext } from 'server/utils/get-required-session-context';
import { match } from 'ts-pattern';
import { getRequiredSession } from '@documenso/auth/server/lib/utils/get-session';
import { AppErrorCode } from '@documenso/lib/errors/app-error';
import { getTeamByUrl } from '@documenso/lib/server-only/team/get-team';
import { getTeams } from '@documenso/lib/server-only/team/get-teams';
import { TrpcProvider } from '@documenso/trpc/react';
import { Button } from '@documenso/ui/primitives/button';
@ -16,43 +14,28 @@ import { TeamProvider } from '~/providers/team';
import type { Route } from './+types/_layout';
export const loader = async ({ request, params }: Route.LoaderArgs) => {
// Todo: get user better from context or something
// Todo: get user better from context or something
const { user } = await getRequiredSession(request);
export const loader = ({ context }: Route.LoaderArgs) => {
const { currentTeam } = getRequiredSessionContext(context);
const [getTeamsPromise, getTeamPromise] = await Promise.allSettled([
getTeams({ userId: user.id }),
getTeamByUrl({ userId: user.id, teamUrl: params.teamUrl }),
]);
console.log('1');
console.log({ userId: user.id, teamUrl: params.teamUrl });
console.log(getTeamPromise.status);
if (getTeamPromise.status === 'rejected') {
console.log('2');
return replace('/documents');
if (!currentTeam) {
return redirect('/documents');
}
const team = getTeamPromise.value;
const teams = getTeamsPromise.status === 'fulfilled' ? getTeamsPromise.value : [];
const trpcHeaders = {
'x-team-Id': team.id.toString(),
'x-team-Id': currentTeam.id.toString(),
};
return {
team,
teams,
currentTeam,
trpcHeaders,
};
};
export default function Layout({ loaderData }: Route.ComponentProps) {
const { team, trpcHeaders } = loaderData;
const { currentTeam, trpcHeaders } = loaderData;
return (
<TeamProvider team={team}>
<TeamProvider team={currentTeam}>
<TrpcProvider headers={trpcHeaders}>
{/* Todo: Do this. */}
{/* {team.subscription && team.subscription.status !== SubscriptionStatus.ACTIVE && (

View File

@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro';
import { CheckCircle2, Clock } from 'lucide-react';
import { P, match } from 'ts-pattern';
import { useSession } from '@documenso/lib/client-only/providers/session';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { extractInitials } from '@documenso/lib/utils/recipient-formatter';
import { isTokenExpired } from '@documenso/lib/utils/token-verification';
@ -16,11 +17,10 @@ import { TeamTransferDialog } from '~/components/dialogs/team-transfer-dialog';
import { AvatarImageForm } from '~/components/forms/avatar-image';
import { TeamEmailDropdown } from '~/components/pages/teams/team-email-dropdown';
import { TeamTransferStatus } from '~/components/pages/teams/team-transfer-status';
import { useAuth } from '~/providers/auth';
import { useCurrentTeam } from '~/providers/team';
export default function TeamsSettingsPage() {
const { user } = useAuth();
const { user } = useSession();
const team = useCurrentTeam();

View File

@ -1,9 +1,7 @@
import { Trans } from '@lingui/macro';
import { Outlet } from 'react-router';
import { getRequiredTeamSessionContext } from 'server/utils/get-required-session-context';
import { getRequiredSession } from '@documenso/auth/server/lib/utils/get-session';
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import { getTeamByUrl } from '@documenso/lib/server-only/team/get-team';
import { canExecuteTeamAction } from '@documenso/lib/utils/teams';
import { TeamSettingsDesktopNav } from '~/components/pages/teams/team-settings-desktop-nav';
@ -11,26 +9,12 @@ import { TeamSettingsMobileNav } from '~/components/pages/teams/team-settings-mo
import type { Route } from '../+types/_layout';
export async function loader({ request, params }: Route.LoaderArgs) {
// Todo: Get from parent loaders...
const { user } = await getRequiredSession(request);
const teamUrl = params.teamUrl;
export async function loader({ context }: Route.LoaderArgs) {
const { currentTeam: team } = getRequiredTeamSessionContext(context);
try {
const team = await getTeamByUrl({ userId: user.id, teamUrl });
if (!canExecuteTeamAction('MANAGE_TEAM', team.currentTeamMember.role)) {
// Unauthorized.
throw new Response(null, { status: 401 }); // Todo: Test
}
} catch (e) {
const error = AppError.parseError(e);
if (error.code === AppErrorCode.NOT_FOUND) {
throw new Response(null, { status: 404 }); // Todo: Test
}
throw e;
// Todo: Test that 404 page shows up from error.
if (!team || !canExecuteTeamAction('MANAGE_TEAM', team.currentTeamMember.role)) {
throw new Response(null, { status: 401 }); // Unauthorized.
}
}

View File

@ -1,12 +1,11 @@
import { Plural, Trans, msg } from '@lingui/macro';
import { useLingui } from '@lingui/react';
import { DateTime } from 'luxon';
import { getRequiredTeamSessionContext } from 'server/utils/get-required-session-context';
import type Stripe from 'stripe';
import { match } from 'ts-pattern';
import { getRequiredSession } from '@documenso/auth/server/lib/utils/get-session';
import { stripe } from '@documenso/lib/server-only/stripe';
import { getTeamByUrl } from '@documenso/lib/server-only/team/get-team';
import { canExecuteTeamAction } from '@documenso/lib/utils/teams';
import { Card, CardContent } from '@documenso/ui/primitives/card';
@ -16,10 +15,8 @@ import { TeamBillingPortalButton } from '~/components/pages/teams/team-billing-p
import type { Route } from './+types/billing';
export async function loader({ request, params }: Route.LoaderArgs) {
const { user } = await getRequiredSession(request);
const team = await getTeamByUrl({ userId: user.id, teamUrl: params.teamUrl });
export async function loader({ context }: Route.LoaderArgs) {
const { currentTeam: team } = getRequiredTeamSessionContext(context);
let teamSubscription: Stripe.Subscription | null = null;

View File

@ -1,14 +1,13 @@
import { getRequiredSession } from '@documenso/auth/server/lib/utils/get-session';
import { getRequiredTeamSessionContext } from 'server/utils/get-required-session-context';
import { getTeamPublicProfile } from '@documenso/lib/server-only/team/get-team-public-profile';
import PublicProfilePage from '~/routes/_authenticated+/settings+/public-profile+/index';
import type { Route } from './+types/public-profile';
export async function loader({ request }: Route.LoaderArgs) {
// Todo: Pull from...
const team = { id: 1 };
const { user } = await getRequiredSession(request);
export async function loader({ context }: Route.LoaderArgs) {
const { user, currentTeam: team } = getRequiredTeamSessionContext(context);
const { profile } = await getTeamPublicProfile({
userId: user.id,
@ -20,4 +19,5 @@ export async function loader({ request }: Route.LoaderArgs) {
};
}
// Todo: Test that the profile shows up correctly for teams.
export default PublicProfilePage;

View File

@ -1,11 +1,10 @@
import { Trans } from '@lingui/macro';
import { useLingui } from '@lingui/react';
import { DateTime } from 'luxon';
import { getRequiredTeamSessionContext } from 'server/utils/get-required-session-context';
import { getRequiredSession } from '@documenso/auth/server/lib/utils/get-session';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { getTeamTokens } from '@documenso/lib/server-only/public-api/get-all-team-tokens';
import { getTeamByUrl } from '@documenso/lib/server-only/team/get-team';
import { Button } from '@documenso/ui/primitives/button';
import DeleteTokenDialog from '~/components/(dashboard)/settings/token/delete-token-dialog';
@ -13,11 +12,8 @@ import { ApiTokenForm } from '~/components/forms/token';
import type { Route } from './+types/tokens';
export async function loader({ request, params }: Route.LoaderArgs) {
const { user } = await getRequiredSession(request); // Todo
// Todo
const team = await getTeamByUrl({ userId: user.id, teamUrl: params.teamUrl });
export async function loader({ context }: Route.LoaderArgs) {
const { user, currentTeam: team } = getRequiredTeamSessionContext(context);
const tokens = await getTeamTokens({ userId: user.id, teamId: team.id }).catch(() => null);

View File

@ -0,0 +1,5 @@
import TemplatePage, { loader } from '~/routes/_authenticated+/templates+/$id._index';
export { loader };
export default TemplatePage;

View File

@ -0,0 +1,5 @@
import TemplateEditPage, { loader } from '~/routes/_authenticated+/templates+/$id.edit';
export { loader };
export default TemplateEditPage;

View File

@ -0,0 +1,5 @@
import TemplatesPage, { meta } from '~/routes/_authenticated+/templates+/_index';
export { meta };
export default TemplatesPage;