mirror of
https://github.com/documenso/documenso.git
synced 2025-11-18 10:42:01 +10:00
chore: flattern routes
This commit is contained in:
@ -33,7 +33,7 @@ import {
|
||||
import { StackAvatarsWithTooltip } from '~/components/general/stack-avatars-with-tooltip';
|
||||
import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
|
||||
|
||||
import type { Route } from './+types/$id._index';
|
||||
import type { Route } from './+types/documents.$id._index';
|
||||
|
||||
export async function loader({ params, request }: Route.LoaderArgs) {
|
||||
const { user } = await getSession(request);
|
||||
@ -16,7 +16,7 @@ import { DocumentStatus } from '~/components/general/document/document-status';
|
||||
import { StackAvatarsWithTooltip } from '~/components/general/stack-avatars-with-tooltip';
|
||||
import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
|
||||
|
||||
import type { Route } from './+types/$id.edit';
|
||||
import type { Route } from './+types/documents.$id.edit';
|
||||
|
||||
export async function loader({ params, request }: Route.LoaderArgs) {
|
||||
const { user } = await getSession(request);
|
||||
@ -22,7 +22,7 @@ import {
|
||||
} from '~/components/general/document/document-status';
|
||||
import { DocumentLogsTable } from '~/components/tables/document-logs-table';
|
||||
|
||||
import type { Route } from './+types/$id.logs';
|
||||
import type { Route } from './+types/documents.$id.logs';
|
||||
|
||||
export async function loader({ params, request }: Route.LoaderArgs) {
|
||||
const { user } = await getSession(request);
|
||||
@ -21,10 +21,10 @@ import { ManagePublicTemplateDialog } from '~/components/dialogs/public-profile-
|
||||
import type { TPublicProfileFormSchema } from '~/components/forms/public-profile-form';
|
||||
import { PublicProfileForm } from '~/components/forms/public-profile-form';
|
||||
import { SettingsHeader } from '~/components/general/settings-header';
|
||||
import { SettingsPublicProfileTemplatesTable } from '~/components/tables/settings-public-profile-templates-table';
|
||||
import { useOptionalCurrentTeam } from '~/providers/team';
|
||||
|
||||
import { SettingsPublicProfileTemplatesTable } from '../../../../components/tables/settings-public-profile-templates-table';
|
||||
import type { Route } from './+types/index';
|
||||
import type { Route } from './+types/public-profile';
|
||||
|
||||
type DirectTemplate = FindTemplateRow & {
|
||||
directLink: Pick<TemplateDirectLink, 'token' | 'enabled'>;
|
||||
@ -16,7 +16,7 @@ import { PasswordForm } from '~/components/forms/password';
|
||||
import { SettingsHeader } from '~/components/general/settings-header';
|
||||
import { appMetaTags } from '~/utils/meta';
|
||||
|
||||
import type { Route } from './+types';
|
||||
import type { Route } from './+types/security';
|
||||
|
||||
export function meta() {
|
||||
return appMetaTags('Security');
|
||||
@ -1,125 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { TeamEmail } from '@prisma/client';
|
||||
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@documenso/ui/primitives/dialog';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
export type TeamEmailUsageProps = {
|
||||
teamEmail: TeamEmail & { team: { name: string; url: string } };
|
||||
};
|
||||
|
||||
export const TeamEmailUsage = ({ teamEmail }: TeamEmailUsageProps) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const { _ } = useLingui();
|
||||
const { toast } = useToast();
|
||||
|
||||
const { mutateAsync: deleteTeamEmail, isPending: isDeletingTeamEmail } =
|
||||
trpc.team.deleteTeamEmail.useMutation({
|
||||
onSuccess: () => {
|
||||
toast({
|
||||
title: _(msg`Success`),
|
||||
description: _(msg`You have successfully revoked access.`),
|
||||
duration: 5000,
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
toast({
|
||||
title: _(msg`Something went wrong`),
|
||||
description: _(
|
||||
msg`We encountered an unknown error while attempting to revoke access. Please try again or contact support.`,
|
||||
),
|
||||
variant: 'destructive',
|
||||
duration: 10000,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Alert variant="neutral" className="flex flex-row items-center justify-between p-6">
|
||||
<div>
|
||||
<AlertTitle className="mb-0">
|
||||
<Trans>Team Email</Trans>
|
||||
</AlertTitle>
|
||||
<AlertDescription>
|
||||
<p>
|
||||
<Trans>
|
||||
Your email is currently being used by team{' '}
|
||||
<span className="font-semibold">{teamEmail.team.name}</span> ({teamEmail.team.url}
|
||||
).
|
||||
</Trans>
|
||||
</p>
|
||||
|
||||
<p className="mt-1">
|
||||
<Trans>They have permission on your behalf to:</Trans>
|
||||
</p>
|
||||
|
||||
<ul className="mt-0.5 list-inside list-disc">
|
||||
<li>
|
||||
<Trans>Display your name and email in documents</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>View all documents sent to your account</Trans>
|
||||
</li>
|
||||
</ul>
|
||||
</AlertDescription>
|
||||
</div>
|
||||
|
||||
<Dialog open={open} onOpenChange={(value) => !isDeletingTeamEmail && setOpen(value)}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="destructive">
|
||||
<Trans>Revoke access</Trans>
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
|
||||
<DialogContent position="center">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
<Trans>Are you sure?</Trans>
|
||||
</DialogTitle>
|
||||
|
||||
<DialogDescription className="mt-4">
|
||||
<Trans>
|
||||
You are about to revoke access for team{' '}
|
||||
<span className="font-semibold">{teamEmail.team.name}</span> ({teamEmail.team.url})
|
||||
to use your email.
|
||||
</Trans>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<fieldset disabled={isDeletingTeamEmail}>
|
||||
<DialogFooter>
|
||||
<Button type="button" variant="secondary" onClick={() => setOpen(false)}>
|
||||
<Trans>Cancel</Trans>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="destructive"
|
||||
loading={isDeletingTeamEmail}
|
||||
onClick={async () => deleteTeamEmail({ teamId: teamEmail.teamId })}
|
||||
>
|
||||
<Trans>Revoke</Trans>
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</fieldset>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Alert>
|
||||
);
|
||||
};
|
||||
@ -1,187 +0,0 @@
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Plural, Trans } from '@lingui/react/macro';
|
||||
import { AnimatePresence } from 'framer-motion';
|
||||
import { BellIcon } from 'lucide-react';
|
||||
|
||||
import { formatAvatarUrl } from '@documenso/lib/utils/avatars';
|
||||
import { formatTeamUrl } from '@documenso/lib/utils/teams';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { AnimateGenericFadeInOut } from '@documenso/ui/components/animate/animate-generic-fade-in-out';
|
||||
import { Alert, AlertDescription } from '@documenso/ui/primitives/alert';
|
||||
import { AvatarWithText } from '@documenso/ui/primitives/avatar';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@documenso/ui/primitives/dialog';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
export const TeamInvitations = () => {
|
||||
const { data, isLoading } = trpc.team.getTeamInvitations.useQuery();
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{data && data.length > 0 && !isLoading && (
|
||||
<AnimateGenericFadeInOut>
|
||||
<Alert variant="secondary">
|
||||
<div className="flex h-full flex-row items-center p-2">
|
||||
<BellIcon className="mr-4 h-5 w-5 text-blue-800" />
|
||||
|
||||
<AlertDescription className="mr-2">
|
||||
<Plural
|
||||
value={data.length}
|
||||
one={
|
||||
<span>
|
||||
You have <strong>1</strong> pending team invitation
|
||||
</span>
|
||||
}
|
||||
other={
|
||||
<span>
|
||||
You have <strong>#</strong> pending team invitations
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
</AlertDescription>
|
||||
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<button className="ml-auto text-sm font-medium text-blue-700 hover:text-blue-600">
|
||||
<Trans>View invites</Trans>
|
||||
</button>
|
||||
</DialogTrigger>
|
||||
|
||||
<DialogContent position="center">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
<Trans>Pending invitations</Trans>
|
||||
</DialogTitle>
|
||||
|
||||
<DialogDescription className="mt-4">
|
||||
<Plural
|
||||
value={data.length}
|
||||
one={
|
||||
<span>
|
||||
You have <strong>1</strong> pending team invitation
|
||||
</span>
|
||||
}
|
||||
other={
|
||||
<span>
|
||||
You have <strong>#</strong> pending team invitations
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<ul className="-mx-6 -mb-6 max-h-[80vh] divide-y overflow-auto px-6 pb-6 xl:max-h-[70vh]">
|
||||
{data.map((invitation) => (
|
||||
<li key={invitation.teamId}>
|
||||
<AvatarWithText
|
||||
avatarSrc={formatAvatarUrl(invitation.team.avatarImageId)}
|
||||
className="w-full max-w-none py-4"
|
||||
avatarFallback={invitation.team.name.slice(0, 1)}
|
||||
primaryText={
|
||||
<span className="text-foreground/80 font-semibold">
|
||||
{invitation.team.name}
|
||||
</span>
|
||||
}
|
||||
secondaryText={formatTeamUrl(invitation.team.url)}
|
||||
rightSideComponent={
|
||||
<div className="ml-auto space-x-2">
|
||||
<DeclineTeamInvitationButton teamId={invitation.team.id} />
|
||||
<AcceptTeamInvitationButton teamId={invitation.team.id} />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</Alert>
|
||||
</AnimateGenericFadeInOut>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
};
|
||||
|
||||
const AcceptTeamInvitationButton = ({ teamId }: { teamId: number }) => {
|
||||
const { _ } = useLingui();
|
||||
const { toast } = useToast();
|
||||
|
||||
const {
|
||||
mutateAsync: acceptTeamInvitation,
|
||||
isPending,
|
||||
isSuccess,
|
||||
} = trpc.team.acceptTeamInvitation.useMutation({
|
||||
onSuccess: () => {
|
||||
toast({
|
||||
title: _(msg`Success`),
|
||||
description: _(msg`Accepted team invitation`),
|
||||
duration: 5000,
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
toast({
|
||||
title: _(msg`Something went wrong`),
|
||||
description: _(msg`Unable to join this team at this time.`),
|
||||
variant: 'destructive',
|
||||
duration: 10000,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={async () => acceptTeamInvitation({ teamId })}
|
||||
loading={isPending}
|
||||
disabled={isPending || isSuccess}
|
||||
>
|
||||
<Trans>Accept</Trans>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
const DeclineTeamInvitationButton = ({ teamId }: { teamId: number }) => {
|
||||
const { _ } = useLingui();
|
||||
const { toast } = useToast();
|
||||
|
||||
const {
|
||||
mutateAsync: declineTeamInvitation,
|
||||
isPending,
|
||||
isSuccess,
|
||||
} = trpc.team.declineTeamInvitation.useMutation({
|
||||
onSuccess: () => {
|
||||
toast({
|
||||
title: _(msg`Success`),
|
||||
description: _(msg`Declined team invitation`),
|
||||
duration: 5000,
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
toast({
|
||||
title: _(msg`Something went wrong`),
|
||||
description: _(msg`Unable to decline this team invitation at this time.`),
|
||||
variant: 'destructive',
|
||||
duration: 10000,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={async () => declineTeamInvitation({ teamId })}
|
||||
loading={isPending}
|
||||
disabled={isPending || isSuccess}
|
||||
variant="ghost"
|
||||
>
|
||||
<Trans>Decline</Trans>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
@ -7,11 +7,10 @@ import { AnimateGenericFadeInOut } from '@documenso/ui/components/animate/animat
|
||||
|
||||
import { TeamCreateDialog } from '~/components/dialogs/team-create-dialog';
|
||||
import { SettingsHeader } from '~/components/general/settings-header';
|
||||
import { TeamEmailUsage } from '~/components/general/teams/team-email-usage';
|
||||
import { TeamInvitations } from '~/components/general/teams/team-invitations';
|
||||
import { UserSettingsTeamsPageDataTable } from '~/components/tables/user-settings-teams-page-table';
|
||||
|
||||
import { TeamEmailUsage } from './team-email-usage';
|
||||
import { TeamInvitations } from './team-invitations';
|
||||
|
||||
export default function TeamsSettingsPage() {
|
||||
const { _ } = useLingui();
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import DocumentPage, { loader } from '~/routes/_authenticated+/documents+/$id._index';
|
||||
import DocumentPage, { loader } from '~/routes/_authenticated+/documents.$id._index';
|
||||
|
||||
export { loader };
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import DocumentEditPage, { loader } from '~/routes/_authenticated+/documents+/$id.edit';
|
||||
import DocumentEditPage, { loader } from '~/routes/_authenticated+/documents.$id.edit';
|
||||
|
||||
export { loader };
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import DocumentLogsPage, { loader } from '~/routes/_authenticated+/documents+/$id.logs';
|
||||
import DocumentLogsPage, { loader } from '~/routes/_authenticated+/documents.$id.logs';
|
||||
|
||||
export { loader };
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import DocumentsPage, { meta } from '~/routes/_authenticated+/documents+/_index';
|
||||
import DocumentsPage, { meta } from '~/routes/_authenticated+/documents._index';
|
||||
|
||||
export { meta };
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ import { SettingsHeader } from '~/components/general/settings-header';
|
||||
import { TeamEmailDropdown } from '~/components/general/teams/team-email-dropdown';
|
||||
import { TeamTransferStatus } from '~/components/general/teams/team-transfer-status';
|
||||
|
||||
import type { Route } from './+types/_index';
|
||||
import type { Route } from './+types/settings._index';
|
||||
|
||||
export async function loader({ request, params }: Route.LoaderArgs) {
|
||||
const { user } = await getSession(request);
|
||||
@ -9,7 +9,7 @@ import { TeamSettingsNavDesktop } from '~/components/general/teams/team-settings
|
||||
import { TeamSettingsNavMobile } from '~/components/general/teams/team-settings-nav-mobile';
|
||||
import { appMetaTags } from '~/utils/meta';
|
||||
|
||||
import type { Route } from './+types/_layout';
|
||||
import type { Route } from './+types/settings._layout';
|
||||
|
||||
export function meta() {
|
||||
return appMetaTags('Team Settings');
|
||||
@ -15,7 +15,7 @@ import { SettingsHeader } from '~/components/general/settings-header';
|
||||
import { TeamBillingPortalButton } from '~/components/general/teams/team-billing-portal-button';
|
||||
import { TeamSettingsBillingInvoicesTable } from '~/components/tables/team-settings-billing-invoices-table';
|
||||
|
||||
import type { Route } from './+types/billing';
|
||||
import type { Route } from './+types/settings.billing';
|
||||
|
||||
export async function loader({ request, params }: Route.LoaderArgs) {
|
||||
const session = await getSession(request);
|
||||
@ -8,7 +8,7 @@ import { TeamBrandingPreferencesForm } from '~/components/forms/team-branding-pr
|
||||
import { TeamDocumentPreferencesForm } from '~/components/forms/team-document-preferences-form';
|
||||
import { SettingsHeader } from '~/components/general/settings-header';
|
||||
|
||||
import type { Route } from './+types/preferences';
|
||||
import type { Route } from './+types/settings.preferences';
|
||||
|
||||
export async function loader({ request, params }: Route.LoaderArgs) {
|
||||
const { user } = await getSession(request);
|
||||
@ -2,9 +2,9 @@ import { getSession } from '@documenso/auth/server/lib/utils/get-session';
|
||||
import { getTeamByUrl } from '@documenso/lib/server-only/team/get-team';
|
||||
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';
|
||||
|
||||
import type { Route } from './+types/public-profile';
|
||||
import type { Route } from './+types/settings.public-profile';
|
||||
|
||||
// Todo: This can be optimized.
|
||||
export async function loader({ request, params }: Route.LoaderArgs) {
|
||||
@ -1,3 +1,3 @@
|
||||
import ApiTokensPage from '~/routes/_authenticated+/settings+/tokens+/index';
|
||||
import ApiTokensPage from '~/routes/_authenticated+/settings+/tokens';
|
||||
|
||||
export default ApiTokensPage;
|
||||
@ -28,7 +28,7 @@ import { SettingsHeader } from '~/components/general/settings-header';
|
||||
import { WebhookMultiSelectCombobox } from '~/components/general/webhook-multiselect-combobox';
|
||||
import { useCurrentTeam } from '~/providers/team';
|
||||
|
||||
import type { Route } from './+types/webhooks.$id';
|
||||
import type { Route } from './+types/settings.webhooks.$id';
|
||||
|
||||
const ZEditWebhookFormSchema = ZEditWebhookMutationSchema.omit({ id: true });
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import TemplatePage, { loader } from '~/routes/_authenticated+/templates+/$id._index';
|
||||
import TemplatePage, { loader } from '~/routes/_authenticated+/templates.$id._index';
|
||||
|
||||
export { loader };
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import TemplateEditPage, { loader } from '~/routes/_authenticated+/templates+/$id.edit';
|
||||
import TemplateEditPage, { loader } from '~/routes/_authenticated+/templates.$id.edit';
|
||||
|
||||
export { loader };
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import TemplatesPage, { meta } from '~/routes/_authenticated+/templates+/_index';
|
||||
import TemplatesPage, { meta } from '~/routes/_authenticated+/templates._index';
|
||||
|
||||
export { meta };
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ import { TemplateType } from '~/components/general/template/template-type';
|
||||
import { TemplatesTableActionDropdown } from '~/components/tables/templates-table-action-dropdown';
|
||||
import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
|
||||
|
||||
import type { Route } from './+types/$id._index';
|
||||
import type { Route } from './+types/templates.$id._index';
|
||||
|
||||
export async function loader({ params, request }: Route.LoaderArgs) {
|
||||
const { user } = await getSession(request);
|
||||
@ -13,8 +13,8 @@ import { TemplateEditForm } from '~/components/general/template/template-edit-fo
|
||||
import { TemplateType } from '~/components/general/template/template-type';
|
||||
import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
|
||||
|
||||
import { TemplateDirectLinkDialogWrapper } from '../../../components/dialogs/template-direct-link-dialog-wrapper';
|
||||
import type { Route } from './+types/$id.edit';
|
||||
import { TemplateDirectLinkDialogWrapper } from '../../components/dialogs/template-direct-link-dialog-wrapper';
|
||||
import type { Route } from './+types/templates.$id.edit';
|
||||
|
||||
export async function loader({ params, request }: Route.LoaderArgs) {
|
||||
const { user } = await getSession(request);
|
||||
Reference in New Issue
Block a user