diff --git a/apps/remix/app/components/tables/documents-table-sender-filter.tsx b/apps/remix/app/components/tables/documents-table-sender-filter.tsx
index 4a44edd51..c4c2bbd4a 100644
--- a/apps/remix/app/components/tables/documents-table-sender-filter.tsx
+++ b/apps/remix/app/components/tables/documents-table-sender-filter.tsx
@@ -1,10 +1,9 @@
-import { msg } from '@lingui/core/macro';
-import { Trans } from '@lingui/react/macro';
-import { useLocation, useNavigate, useSearchParams } from 'react-router';
-
import { useIsMounted } from '@documenso/lib/client-only/hooks/use-is-mounted';
import { trpc } from '@documenso/trpc/react';
import { MultiSelectCombobox } from '@documenso/ui/primitives/multi-select-combobox';
+import { msg } from '@lingui/core/macro';
+import { Trans } from '@lingui/react/macro';
+import { useLocation, useNavigate, useSearchParams } from 'react-router';
type DocumentsTableSenderFilterProps = {
teamId: number;
@@ -17,9 +16,7 @@ export const DocumentsTableSenderFilter = ({ teamId }: DocumentsTableSenderFilte
const isMounted = useIsMounted();
- const senderIds = (searchParams?.get('senderIds') ?? '')
- .split(',')
- .filter((value) => value !== '');
+ const senderIds = (searchParams?.get('senderIds') ?? '').split(',').filter((value) => value !== '');
const { data, isLoading } = trpc.team.member.getMany.useQuery({
teamId,
@@ -49,7 +46,7 @@ export const DocumentsTableSenderFilter = ({ teamId }: DocumentsTableSenderFilte
return (
+
Sender: All
diff --git a/apps/remix/app/components/tables/documents-table-title.tsx b/apps/remix/app/components/tables/documents-table-title.tsx
index 914a59625..b9ff67c2e 100644
--- a/apps/remix/app/components/tables/documents-table-title.tsx
+++ b/apps/remix/app/components/tables/documents-table-title.tsx
@@ -1,10 +1,9 @@
-import { Link } from 'react-router';
-import { match } from 'ts-pattern';
-
import { useSession } from '@documenso/lib/client-only/providers/session';
import type { TDocumentMany as TDocumentRow } from '@documenso/lib/types/document';
import { findRecipientByEmail } from '@documenso/lib/utils/recipients';
import { formatDocumentsPath } from '@documenso/lib/utils/teams';
+import { Link } from 'react-router';
+import { match } from 'ts-pattern';
import { useCurrentTeam } from '~/providers/team';
@@ -53,8 +52,6 @@ export const DataTableTitle = ({ row, teamUrl }: DataTableTitleProps) => {
))
.otherwise(() => (
-
- {row.title}
-
+ {row.title}
));
};
diff --git a/apps/remix/app/components/tables/documents-table.tsx b/apps/remix/app/components/tables/documents-table.tsx
index 7f1d104dd..ddffc8a9c 100644
--- a/apps/remix/app/components/tables/documents-table.tsx
+++ b/apps/remix/app/components/tables/documents-table.tsx
@@ -1,12 +1,3 @@
-import { useMemo, useTransition } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Loader } from 'lucide-react';
-import { DateTime } from 'luxon';
-import { Link } from 'react-router';
-import { match } from 'ts-pattern';
-
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { useSession } from '@documenso/lib/client-only/providers/session';
import { isDocumentCompleted } from '@documenso/lib/utils/document';
@@ -19,6 +10,13 @@ import { DataTable } from '@documenso/ui/primitives/data-table';
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { TableCell } from '@documenso/ui/primitives/table';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Loader } from 'lucide-react';
+import { DateTime } from 'luxon';
+import { useMemo, useTransition } from 'react';
+import { Link } from 'react-router';
+import { match } from 'ts-pattern';
import { DocumentStatus } from '~/components/general/document/document-status';
import { useCurrentTeam } from '~/providers/team';
@@ -87,18 +85,11 @@ export const DocumentsTable = ({
{
header: _(msg`Created`),
accessorKey: 'createdAt',
- cell: ({ row }) =>
- i18n.date(row.original.createdAt, { ...DateTime.DATETIME_SHORT, hourCycle: 'h12' }),
+ cell: ({ row }) => i18n.date(row.original.createdAt, { ...DateTime.DATETIME_SHORT, hourCycle: 'h12' }),
},
{
header: _(msg`Title`),
- cell: ({ row }) => (
-
- ),
+ cell: ({ row }) => ,
},
{
id: 'sender',
@@ -109,10 +100,7 @@ export const DocumentsTable = ({
header: _(msg`Recipient`),
accessorKey: 'recipient',
cell: ({ row }) => (
-
+
),
},
{
@@ -263,8 +251,6 @@ const DataTableTitle = ({ row, teamUrl, teamEmail }: DataTableTitleProps) => {
))
.otherwise(() => (
-
- {row.title}
-
+ {row.title}
));
};
diff --git a/apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx b/apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx
index c3df6fda9..6bcc4b145 100644
--- a/apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx
+++ b/apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx
@@ -1,10 +1,7 @@
-import { useEffect } from 'react';
-
-import { useLingui } from '@lingui/react/macro';
-import { Trans } from '@lingui/react/macro';
-import { DownloadIcon, FolderInputIcon, Trash2Icon, XIcon } from 'lucide-react';
-
import { Button } from '@documenso/ui/primitives/button';
+import { Trans, useLingui } from '@lingui/react/macro';
+import { DownloadIcon, FolderInputIcon, Trash2Icon, XIcon } from 'lucide-react';
+import { useEffect } from 'react';
export type EnvelopesTableBulkActionBarProps = {
selectedCount: number;
@@ -45,10 +42,10 @@ export const EnvelopesTableBulkActionBar = ({
return (
-
+
{selectedCount}
-
+
selected
@@ -60,7 +57,7 @@ export const EnvelopesTableBulkActionBar = ({
variant="ghost"
size="sm"
onClick={onMoveClick}
- className="h-8 gap-x-1.5 py-1.5 pl-2 pr-2.5"
+ className="h-8 gap-x-1.5 py-1.5 pr-2.5 pl-2"
>
Move
@@ -72,7 +69,7 @@ export const EnvelopesTableBulkActionBar = ({
variant="ghost"
size="sm"
onClick={onDownloadClick}
- className="h-8 gap-x-1.5 py-1.5 pl-2 pr-2.5"
+ className="h-8 gap-x-1.5 py-1.5 pr-2.5 pl-2"
>
Download
@@ -84,7 +81,7 @@ export const EnvelopesTableBulkActionBar = ({
variant="ghost"
size="sm"
onClick={onDeleteClick}
- className="h-8 gap-x-1.5 py-1.5 pl-2 pr-2.5 text-destructive hover:bg-destructive/10 hover:text-destructive"
+ className="h-8 gap-x-1.5 py-1.5 pr-2.5 pl-2 text-destructive hover:bg-destructive/10 hover:text-destructive"
>
Delete
diff --git a/apps/remix/app/components/tables/inbox-table.tsx b/apps/remix/app/components/tables/inbox-table.tsx
index eb72219b4..d0d6a9e21 100644
--- a/apps/remix/app/components/tables/inbox-table.tsx
+++ b/apps/remix/app/components/tables/inbox-table.tsx
@@ -1,15 +1,3 @@
-import { useMemo, useTransition } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import { DocumentStatus as DocumentStatusEnum } from '@prisma/client';
-import { RecipientRole, SigningStatus } from '@prisma/client';
-import { CheckCircleIcon, DownloadIcon, EyeIcon, Loader, PencilIcon } from 'lucide-react';
-import { DateTime } from 'luxon';
-import { Link, useSearchParams } from 'react-router';
-import { match } from 'ts-pattern';
-
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { useSession } from '@documenso/lib/client-only/providers/session';
import { isDocumentCompleted } from '@documenso/lib/utils/document';
@@ -22,6 +10,15 @@ import { DataTablePagination } from '@documenso/ui/primitives/data-table-paginat
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { TableCell } from '@documenso/ui/primitives/table';
import { useToast } from '@documenso/ui/primitives/use-toast';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { DocumentStatus as DocumentStatusEnum, RecipientRole, SigningStatus } from '@prisma/client';
+import { CheckCircleIcon, DownloadIcon, EyeIcon, Loader, PencilIcon } from 'lucide-react';
+import { DateTime } from 'luxon';
+import { useMemo, useTransition } from 'react';
+import { Link, useSearchParams } from 'react-router';
+import { match } from 'ts-pattern';
import { DocumentStatus } from '~/components/general/document/document-status';
import { useOptionalCurrentTeam } from '~/providers/team';
@@ -59,15 +56,12 @@ export const InboxTable = () => {
{
header: _(msg`Created`),
accessorKey: 'createdAt',
- cell: ({ row }) =>
- i18n.date(row.original.createdAt, { ...DateTime.DATETIME_SHORT, hourCycle: 'h12' }),
+ cell: ({ row }) => i18n.date(row.original.createdAt, { ...DateTime.DATETIME_SHORT, hourCycle: 'h12' }),
},
{
header: _(msg`Title`),
cell: ({ row }) => (
-
- {row.original.title}
-
+
{row.original.title}
),
},
{
@@ -79,10 +73,7 @@ export const InboxTable = () => {
header: _(msg`Recipient`),
accessorKey: 'recipient',
cell: ({ row }) => (
-
+
),
},
{
@@ -130,7 +121,7 @@ export const InboxTable = () => {
enable: isLoadingError || false,
}}
emptyState={
-
+
Documents that require your attention will appear here
@@ -163,15 +154,13 @@ export const InboxTable = () => {
}}
>
{(table) =>
- results.totalPages > 1 && (
-
- )
+ results.totalPages > 1 &&
}
{isPending && (
-
@@ -215,19 +204,19 @@ export const InboxTableActionButton = ({ row }: InboxTableActionButtonProps) =>
{match(role)
.with(RecipientRole.SIGNER, () => (
<>
-
+
Sign
>
))
.with(RecipientRole.APPROVER, () => (
<>
-
+
Approve
>
))
.otherwise(() => (
<>
-
+
View
>
))}
@@ -236,7 +225,7 @@ export const InboxTableActionButton = ({ row }: InboxTableActionButtonProps) =>
))
.with({ isPending: true, isSigned: true }, () => (
-
+
View
))
@@ -247,7 +236,7 @@ export const InboxTableActionButton = ({ row }: InboxTableActionButtonProps) =>
token={recipient?.token}
trigger={
-
+
Download
}
diff --git a/apps/remix/app/components/tables/internal-audit-log-table.tsx b/apps/remix/app/components/tables/internal-audit-log-table.tsx
index 5449bb052..03cff1d83 100644
--- a/apps/remix/app/components/tables/internal-audit-log-table.tsx
+++ b/apps/remix/app/components/tables/internal-audit-log-table.tsx
@@ -1,19 +1,15 @@
+import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n';
+import { DOCUMENT_AUDIT_LOG_TYPE, type TDocumentAuditLog } from '@documenso/lib/types/document-audit-logs';
+import { formatDocumentAuditLogAction } from '@documenso/lib/utils/document-audit-logs';
+import { cn } from '@documenso/ui/lib/utils';
+import { Card, CardContent } from '@documenso/ui/primitives/card';
import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react';
import type { DateTimeFormatOptions } from 'luxon';
import { DateTime } from 'luxon';
-import { P, match } from 'ts-pattern';
+import { match, P } from 'ts-pattern';
import { UAParser } from 'ua-parser-js';
-import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n';
-import {
- DOCUMENT_AUDIT_LOG_TYPE,
- type TDocumentAuditLog,
-} from '@documenso/lib/types/document-audit-logs';
-import { formatDocumentAuditLogAction } from '@documenso/lib/utils/document-audit-logs';
-import { cn } from '@documenso/ui/lib/utils';
-import { Card, CardContent } from '@documenso/ui/primitives/card';
-
export type AuditLogDataTableProps = {
logs: TDocumentAuditLog[];
};
@@ -33,10 +29,7 @@ const getAuditLogIndicatorColor = (type: string) =>
.with(DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_RECIPIENT_REJECTED, () => 'bg-red-500')
.with(DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_SENT, () => 'bg-orange-500')
.with(
- P.union(
- DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_FIELD_INSERTED,
- DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_FIELD_UNINSERTED,
- ),
+ P.union(DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_FIELD_INSERTED, DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_FIELD_UNINSERTED),
() => 'bg-blue-500',
)
.otherwise(() => 'bg-muted');
@@ -90,22 +83,20 @@ export const InternalAuditLogTable = ({ logs }: AuditLogDataTableProps) => {
{/* Header Section with indicator, event type, and timestamp */}
-
+
-
+
{log.type.replace(/_/g, ' ')}
-
+
{formattedAction.description}
-
+
{DateTime.fromJSDate(log.createdAt)
.setLocale(APP_I18N_OPTIONS.defaultLocale)
.toLocaleString(dateFormat)}
@@ -117,15 +108,13 @@ export const InternalAuditLogTable = ({ logs }: AuditLogDataTableProps) => {
{/* Details Section - Two column layout */}
-
- {_(msg`User`)}
-
+
{_(msg`User`)}
{log.email || 'N/A'}
-
+
{_(msg`IP Address`)}
@@ -133,13 +122,11 @@ export const InternalAuditLogTable = ({ logs }: AuditLogDataTableProps) => {
-
+
{_(msg`User Agent`)}
-
- {_(formatUserAgent(log.userAgent, userAgentInfo))}
-
+
{_(formatUserAgent(log.userAgent, userAgentInfo))}
diff --git a/apps/remix/app/components/tables/organisation-billing-invoices-table.tsx b/apps/remix/app/components/tables/organisation-billing-invoices-table.tsx
index 9cc84d903..19cf98cda 100644
--- a/apps/remix/app/components/tables/organisation-billing-invoices-table.tsx
+++ b/apps/remix/app/components/tables/organisation-billing-invoices-table.tsx
@@ -1,18 +1,16 @@
-import { useMemo } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import { File } from 'lucide-react';
-import { DateTime } from 'luxon';
-import { Link } from 'react-router';
-
import { trpc } from '@documenso/trpc/react';
import { Button } from '@documenso/ui/primitives/button';
import type { DataTableColumnDef } from '@documenso/ui/primitives/data-table';
import { DataTable } from '@documenso/ui/primitives/data-table';
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { TableCell } from '@documenso/ui/primitives/table';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { File } from 'lucide-react';
+import { DateTime } from 'luxon';
+import { useMemo } from 'react';
+import { Link } from 'react-router';
export type OrganisationBillingInvoicesTableProps = {
organisationId: string;
@@ -59,7 +57,7 @@ export const OrganisationBillingInvoicesTable = ({
-
+
{DateTime.fromSeconds(row.original.created).toFormat('MMMM yyyy')}
@@ -87,21 +85,13 @@ export const OrganisationBillingInvoicesTable = ({
id: 'actions',
cell: ({ row }) => (
-
+
View
-
+
Download
diff --git a/apps/remix/app/components/tables/organisation-email-domains-table.tsx b/apps/remix/app/components/tables/organisation-email-domains-table.tsx
index e864b02a3..a1fdf3e05 100644
--- a/apps/remix/app/components/tables/organisation-email-domains-table.tsx
+++ b/apps/remix/app/components/tables/organisation-email-domains-table.tsx
@@ -1,11 +1,3 @@
-import { useMemo } from 'react';
-
-import { Trans, useLingui } from '@lingui/react/macro';
-import { EmailDomainStatus } from '@prisma/client';
-import { CheckCircle2Icon, ClockIcon } from 'lucide-react';
-import { Link, useSearchParams } from 'react-router';
-import { match } from 'ts-pattern';
-
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
import { ZUrlSearchParamsSchema } from '@documenso/lib/types/search-params';
@@ -20,6 +12,12 @@ import { DataTablePagination } from '@documenso/ui/primitives/data-table-paginat
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { TableCell } from '@documenso/ui/primitives/table';
import { useToast } from '@documenso/ui/primitives/use-toast';
+import { Trans, useLingui } from '@lingui/react/macro';
+import { EmailDomainStatus } from '@prisma/client';
+import { CheckCircle2Icon, ClockIcon } from 'lucide-react';
+import { useMemo } from 'react';
+import { Link, useSearchParams } from 'react-router';
+import { match } from 'ts-pattern';
import { OrganisationEmailDomainDeleteDialog } from '../dialogs/organisation-email-domain-delete-dialog';
@@ -43,18 +41,17 @@ export const OrganisationEmailDomainsDataTable = () => {
},
});
- const { data, isLoading, isLoadingError } =
- trpc.enterprise.organisation.emailDomain.find.useQuery(
- {
- organisationId: organisation.id,
- query: parsedSearchParams.query,
- page: parsedSearchParams.page,
- perPage: parsedSearchParams.perPage,
- },
- {
- placeholderData: (previousData) => previousData,
- },
- );
+ const { data, isLoading, isLoadingError } = trpc.enterprise.organisation.emailDomain.find.useQuery(
+ {
+ organisationId: organisation.id,
+ query: parsedSearchParams.query,
+ page: parsedSearchParams.page,
+ perPage: parsedSearchParams.perPage,
+ },
+ {
+ placeholderData: (previousData) => previousData,
+ },
+ );
const onPaginationChange = (page: number, perPage: number) => {
updateSearchParams({
@@ -105,9 +102,7 @@ export const OrganisationEmailDomainsDataTable = () => {
cell: ({ row }) => (
-
- Manage
-
+ Manage
{
}}
>
{(table) =>
- results.totalPages > 1 && (
-
- )
+ results.totalPages > 1 &&
}
{results.data.length > 0 && (
-
+
Sync Email Domains
-
- This will check and sync the status of all email domains for this organisation
-
+ This will check and sync the status of all email domains for this organisation
diff --git a/apps/remix/app/components/tables/organisation-groups-table.tsx b/apps/remix/app/components/tables/organisation-groups-table.tsx
index 5656c7580..a6e586d85 100644
--- a/apps/remix/app/components/tables/organisation-groups-table.tsx
+++ b/apps/remix/app/components/tables/organisation-groups-table.tsx
@@ -1,11 +1,3 @@
-import { useMemo } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import { OrganisationGroupType } from '@prisma/client';
-import { Link, useSearchParams } from 'react-router';
-
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
import { EXTENDED_ORGANISATION_MEMBER_ROLE_MAP } from '@documenso/lib/constants/organisations-translations';
@@ -17,6 +9,12 @@ import { DataTable } from '@documenso/ui/primitives/data-table';
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { TableCell } from '@documenso/ui/primitives/table';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { OrganisationGroupType } from '@prisma/client';
+import { useMemo } from 'react';
+import { Link, useSearchParams } from 'react-router';
import { OrganisationGroupDeleteDialog } from '../dialogs/organisation-group-delete-dialog';
@@ -141,11 +139,7 @@ export const OrganisationGroupsDataTable = () => {
),
}}
>
- {(table) =>
- results.totalPages > 1 && (
-
- )
- }
+ {(table) => results.totalPages > 1 && }
);
};
diff --git a/apps/remix/app/components/tables/organisation-insights-table.tsx b/apps/remix/app/components/tables/organisation-insights-table.tsx
index 5d6c5dc44..30d52b859 100644
--- a/apps/remix/app/components/tables/organisation-insights-table.tsx
+++ b/apps/remix/app/components/tables/organisation-insights-table.tsx
@@ -1,11 +1,3 @@
-import { useTransition } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Building2, Loader, TrendingUp, Users } from 'lucide-react';
-import { Link } from 'react-router';
-import { useNavigation } from 'react-router';
-
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import type { OrganisationDetailedInsights } from '@documenso/lib/server-only/admin/get-organisation-detailed-insights';
import type { DateRange } from '@documenso/lib/types/search-params';
@@ -14,6 +6,11 @@ import { Button } from '@documenso/ui/primitives/button';
import type { DataTableColumnDef } from '@documenso/ui/primitives/data-table';
import { DataTable } from '@documenso/ui/primitives/data-table';
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Building2, Loader, TrendingUp, Users } from 'lucide-react';
+import { useTransition } from 'react';
+import { Link, useNavigation } from 'react-router';
import { DateRangeFilter } from '~/components/filters/date-range-filter';
import { DocumentStatus } from '~/components/general/document/document-status';
@@ -63,10 +60,7 @@ export const OrganisationInsightsTable = ({
header: _(msg`Team Name`),
accessorKey: 'name',
cell: ({ row }) => (
-
+
{row.getValue('name')}
),
@@ -97,10 +91,7 @@ export const OrganisationInsightsTable = ({
header: () => {_(msg`Name`)} ,
accessorKey: 'name',
cell: ({ row }) => (
-
+
{(row.getValue('name') as string) || (row.getValue('email') as string)}
),
@@ -150,9 +141,7 @@ export const OrganisationInsightsTable = ({
{
header: () => {_(msg`Status`)} ,
accessorKey: 'status',
- cell: ({ row }) => (
-
- ),
+ cell: ({ row }) => ,
size: 120,
},
{
@@ -286,9 +275,9 @@ const SummaryCard = ({
-
{title}
-
{value}
- {subtitle &&
{subtitle}
}
+
{title}
+
{value}
+ {subtitle &&
{subtitle}
}
);
diff --git a/apps/remix/app/components/tables/organisation-member-invites-table.tsx b/apps/remix/app/components/tables/organisation-member-invites-table.tsx
index 5ce733df6..08cd46ee4 100644
--- a/apps/remix/app/components/tables/organisation-member-invites-table.tsx
+++ b/apps/remix/app/components/tables/organisation-member-invites-table.tsx
@@ -1,12 +1,3 @@
-import { useMemo } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import { OrganisationMemberInviteStatus } from '@prisma/client';
-import { History, MoreHorizontal, Trash2 } from 'lucide-react';
-import { useSearchParams } from 'react-router';
-
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
import { ORGANISATION_MEMBER_ROLE_MAP } from '@documenso/lib/constants/organisations-translations';
@@ -27,6 +18,13 @@ import {
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { TableCell } from '@documenso/ui/primitives/table';
import { useToast } from '@documenso/ui/primitives/use-toast';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { OrganisationMemberInviteStatus } from '@prisma/client';
+import { History, MoreHorizontal, Trash2 } from 'lucide-react';
+import { useMemo } from 'react';
+import { useSearchParams } from 'react-router';
export const OrganisationMemberInvitesTable = () => {
const [searchParams] = useSearchParams();
@@ -51,39 +49,37 @@ export const OrganisationMemberInvitesTable = () => {
},
);
- const { mutateAsync: resendOrganisationMemberInvitation } =
- trpc.organisation.member.invite.resend.useMutation({
- onSuccess: () => {
- toast({
- title: _(msg`Success`),
- description: _(msg`Invitation has been resent`),
- });
- },
- onError: () => {
- toast({
- title: _(msg`Something went wrong`),
- description: _(msg`Unable to resend invitation. Please try again.`),
- variant: 'destructive',
- });
- },
- });
+ const { mutateAsync: resendOrganisationMemberInvitation } = trpc.organisation.member.invite.resend.useMutation({
+ onSuccess: () => {
+ toast({
+ title: _(msg`Success`),
+ description: _(msg`Invitation has been resent`),
+ });
+ },
+ onError: () => {
+ toast({
+ title: _(msg`Something went wrong`),
+ description: _(msg`Unable to resend invitation. Please try again.`),
+ variant: 'destructive',
+ });
+ },
+ });
- const { mutateAsync: deleteOrganisationMemberInvitations } =
- trpc.organisation.member.invite.deleteMany.useMutation({
- onSuccess: () => {
- toast({
- title: _(msg`Success`),
- description: _(msg`Invitation has been deleted`),
- });
- },
- onError: () => {
- toast({
- title: _(msg`Something went wrong`),
- description: _(msg`Unable to delete invitation. Please try again.`),
- variant: 'destructive',
- });
- },
- });
+ const { mutateAsync: deleteOrganisationMemberInvitations } = trpc.organisation.member.invite.deleteMany.useMutation({
+ onSuccess: () => {
+ toast({
+ title: _(msg`Success`),
+ description: _(msg`Invitation has been deleted`),
+ });
+ },
+ onError: () => {
+ toast({
+ title: _(msg`Something went wrong`),
+ description: _(msg`Unable to delete invitation. Please try again.`),
+ variant: 'destructive',
+ });
+ },
+ });
const onPaginationChange = (page: number, perPage: number) => {
updateSearchParams({
@@ -108,9 +104,7 @@ export const OrganisationMemberInvitesTable = () => {
{row.original.email}
- }
+ primaryText={{row.original.email} }
/>
);
},
@@ -208,11 +202,7 @@ export const OrganisationMemberInvitesTable = () => {
),
}}
>
- {(table) =>
- results.totalPages > 1 && (
-
- )
- }
+ {(table) => results.totalPages > 1 && }
);
};
diff --git a/apps/remix/app/components/tables/organisation-members-table.tsx b/apps/remix/app/components/tables/organisation-members-table.tsx
index 8295efe2a..f98fc1889 100644
--- a/apps/remix/app/components/tables/organisation-members-table.tsx
+++ b/apps/remix/app/components/tables/organisation-members-table.tsx
@@ -1,12 +1,3 @@
-import { useMemo } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import { OrganisationGroupType } from '@prisma/client';
-import { Edit, MoreHorizontal, Trash2 } from 'lucide-react';
-import { useSearchParams } from 'react-router';
-
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
import { EXTENDED_ORGANISATION_MEMBER_ROLE_MAP } from '@documenso/lib/constants/organisations-translations';
@@ -27,6 +18,13 @@ import {
} from '@documenso/ui/primitives/dropdown-menu';
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { TableCell } from '@documenso/ui/primitives/table';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { OrganisationGroupType } from '@prisma/client';
+import { Edit, MoreHorizontal, Trash2 } from 'lucide-react';
+import { useMemo } from 'react';
+import { useSearchParams } from 'react-router';
import { OrganisationMemberDeleteDialog } from '~/components/dialogs/organisation-member-delete-dialog';
import { OrganisationMemberUpdateDialog } from '~/components/dialogs/organisation-member-update-dialog';
@@ -79,9 +77,7 @@ export const OrganisationMembersDataTable = () => {
{row.original.name}
- }
+ primaryText={{row.original.name} }
secondaryText={row.original.email}
/>
);
@@ -102,15 +98,14 @@ export const OrganisationMembersDataTable = () => {
},
{
header: _(msg`Groups`),
- cell: ({ row }) =>
- row.original.groups.filter((group) => group.type === OrganisationGroupType.CUSTOM).length,
+ cell: ({ row }) => row.original.groups.filter((group) => group.type === OrganisationGroupType.CUSTOM).length,
},
{
header: _(msg`Actions`),
cell: ({ row }) => (
-
+
@@ -209,11 +204,7 @@ export const OrganisationMembersDataTable = () => {
),
}}
>
- {(table) =>
- results.totalPages > 1 && (
-
- )
- }
+ {(table) => results.totalPages > 1 && }
);
};
diff --git a/apps/remix/app/components/tables/organisation-teams-table.tsx b/apps/remix/app/components/tables/organisation-teams-table.tsx
index 73632814f..86d1e2161 100644
--- a/apps/remix/app/components/tables/organisation-teams-table.tsx
+++ b/apps/remix/app/components/tables/organisation-teams-table.tsx
@@ -1,11 +1,3 @@
-import { useMemo } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import { useSearchParams } from 'react-router';
-import { Link } from 'react-router';
-
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
@@ -19,6 +11,11 @@ import { DataTable } from '@documenso/ui/primitives/data-table';
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { TableCell } from '@documenso/ui/primitives/table';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { useMemo } from 'react';
+import { Link, useSearchParams } from 'react-router';
import { TeamDeleteDialog } from '../dialogs/team-delete-dialog';
@@ -63,9 +60,7 @@ export const OrganisationTeamsTable = () => {
avatarSrc={formatAvatarUrl(row.original.avatarImageId)}
avatarClass="h-12 w-12"
avatarFallback={row.original.name.slice(0, 1).toUpperCase()}
- primaryText={
- {row.original.name}
- }
+ primaryText={{row.original.name} }
secondaryText={`${NEXT_PUBLIC_WEBAPP_URL()}/t/${row.original.url}`}
/>
@@ -143,11 +138,7 @@ export const OrganisationTeamsTable = () => {
),
}}
>
- {(table) =>
- results.totalPages > 1 && (
-
- )
- }
+ {(table) => results.totalPages > 1 && }
);
};
diff --git a/apps/remix/app/components/tables/settings-public-profile-templates-table.tsx b/apps/remix/app/components/tables/settings-public-profile-templates-table.tsx
index 6fa8f1d07..1a2593000 100644
--- a/apps/remix/app/components/tables/settings-public-profile-templates-table.tsx
+++ b/apps/remix/app/components/tables/settings-public-profile-templates-table.tsx
@@ -1,11 +1,3 @@
-import { useMemo, useState } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import { type TemplateDirectLink, TemplateType } from '@prisma/client';
-import { EditIcon, FileIcon, LinkIcon, MoreHorizontalIcon, Trash2Icon } from 'lucide-react';
-
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
import { formatDirectTemplatePath } from '@documenso/lib/utils/templates';
import { trpc } from '@documenso/trpc/react';
@@ -19,6 +11,12 @@ import {
} from '@documenso/ui/primitives/dropdown-menu';
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { useToast } from '@documenso/ui/primitives/use-toast';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { type TemplateDirectLink, TemplateType } from '@prisma/client';
+import { EditIcon, FileIcon, LinkIcon, MoreHorizontalIcon, Trash2Icon } from 'lucide-react';
+import { useMemo, useState } from 'react';
import { ManagePublicTemplateDialog } from '~/components/dialogs/public-profile-template-manage-dialog';
@@ -82,10 +80,7 @@ export const SettingsPublicProfileTemplatesTable = () => {
Array(3)
.fill(0)
.map((_, index) => (
-
+
@@ -100,7 +95,7 @@ export const SettingsPublicProfileTemplatesTable = () => {
))}
{isLoadingError && (
-
+
Unable to load your public profile templates at this time
{
@@ -114,7 +109,7 @@ export const SettingsPublicProfileTemplatesTable = () => {
)}
{!isLoading && (
-
+
No public profile templates found
{
{/* Public templates list. */}
{publicDirectTemplates.map((template) => (
-
+
-
+
{template.publicTitle}
-
{template.publicDescription}
+
{template.publicDescription}
diff --git a/apps/remix/app/components/tables/settings-security-activity-table.tsx b/apps/remix/app/components/tables/settings-security-activity-table.tsx
index 18bba7d62..79cb0fc66 100644
--- a/apps/remix/app/components/tables/settings-security-activity-table.tsx
+++ b/apps/remix/app/components/tables/settings-security-activity-table.tsx
@@ -1,12 +1,3 @@
-import { useMemo } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import type { DateTimeFormatOptions } from 'luxon';
-import { DateTime } from 'luxon';
-import { useLocation, useNavigate, useSearchParams } from 'react-router';
-import { UAParser } from 'ua-parser-js';
-
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { USER_SECURITY_AUDIT_LOG_MAP } from '@documenso/lib/constants/auth';
import { ZUrlSearchParamsSchema } from '@documenso/lib/types/search-params';
@@ -16,6 +7,13 @@ import { DataTable } from '@documenso/ui/primitives/data-table';
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { TableCell } from '@documenso/ui/primitives/table';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import type { DateTimeFormatOptions } from 'luxon';
+import { DateTime } from 'luxon';
+import { useMemo } from 'react';
+import { useLocation, useNavigate, useSearchParams } from 'react-router';
+import { UAParser } from 'ua-parser-js';
const dateFormat: DateTimeFormatOptions = {
...DateTime.DATETIME_SHORT,
diff --git a/apps/remix/app/components/tables/settings-security-passkey-table-actions.tsx b/apps/remix/app/components/tables/settings-security-passkey-table-actions.tsx
index c14ae8036..7feb0e191 100644
--- a/apps/remix/app/components/tables/settings-security-passkey-table-actions.tsx
+++ b/apps/remix/app/components/tables/settings-security-passkey-table-actions.tsx
@@ -1,12 +1,3 @@
-import { useState } from 'react';
-
-import { zodResolver } from '@hookform/resolvers/zod';
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import { useForm } from 'react-hook-form';
-import { z } from 'zod';
-
import { trpc } from '@documenso/trpc/react';
import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button';
@@ -20,16 +11,16 @@ import {
DialogTitle,
DialogTrigger,
} from '@documenso/ui/primitives/dialog';
-import {
- Form,
- FormControl,
- FormField,
- FormItem,
- FormLabel,
- FormMessage,
-} from '@documenso/ui/primitives/form/form';
+import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
import { Input } from '@documenso/ui/primitives/input';
import { useToast } from '@documenso/ui/primitives/use-toast';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { useState } from 'react';
+import { useForm } from 'react-hook-form';
+import { z } from 'zod';
export type SettingsSecurityPasskeyTableActionsProps = {
className?: string;
@@ -61,56 +52,47 @@ export const SettingsSecurityPasskeyTableActions = ({
},
});
- const { mutateAsync: updatePasskey, isPending: isUpdatingPasskey } =
- trpc.auth.passkey.update.useMutation({
- onSuccess: () => {
- toast({
- title: _(msg`Success`),
- description: _(msg`Passkey has been updated`),
- });
+ const { mutateAsync: updatePasskey, isPending: isUpdatingPasskey } = trpc.auth.passkey.update.useMutation({
+ onSuccess: () => {
+ toast({
+ title: _(msg`Success`),
+ description: _(msg`Passkey has been updated`),
+ });
- setIsUpdateDialogOpen(false);
- },
- onError: () => {
- toast({
- title: _(msg`Something went wrong`),
- description: _(
- msg`We are unable to update this passkey at the moment. Please try again later.`,
- ),
- duration: 10000,
- variant: 'destructive',
- });
- },
- });
+ setIsUpdateDialogOpen(false);
+ },
+ onError: () => {
+ toast({
+ title: _(msg`Something went wrong`),
+ description: _(msg`We are unable to update this passkey at the moment. Please try again later.`),
+ duration: 10000,
+ variant: 'destructive',
+ });
+ },
+ });
- const { mutateAsync: deletePasskey, isPending: isDeletingPasskey } =
- trpc.auth.passkey.delete.useMutation({
- onSuccess: () => {
- toast({
- title: _(msg`Success`),
- description: _(msg`Passkey has been removed`),
- });
+ const { mutateAsync: deletePasskey, isPending: isDeletingPasskey } = trpc.auth.passkey.delete.useMutation({
+ onSuccess: () => {
+ toast({
+ title: _(msg`Success`),
+ description: _(msg`Passkey has been removed`),
+ });
- setIsDeleteDialogOpen(false);
- },
- onError: () => {
- toast({
- title: _(msg`Something went wrong`),
- description: _(
- msg`We are unable to remove this passkey at the moment. Please try again later.`,
- ),
- duration: 10000,
- variant: 'destructive',
- });
- },
- });
+ setIsDeleteDialogOpen(false);
+ },
+ onError: () => {
+ toast({
+ title: _(msg`Something went wrong`),
+ description: _(msg`We are unable to remove this passkey at the moment. Please try again later.`),
+ duration: 10000,
+ variant: 'destructive',
+ });
+ },
+ });
return (
-
!isUpdatingPasskey && setIsUpdateDialogOpen(value)}
- >
+ !isUpdatingPasskey && setIsUpdateDialogOpen(value)}>
e.stopPropagation()} asChild>
Edit
@@ -173,10 +155,7 @@ export const SettingsSecurityPasskeyTableActions = ({
- !isDeletingPasskey && setIsDeleteDialogOpen(value)}
- >
+ !isDeletingPasskey && setIsDeleteDialogOpen(value)}>
e.stopPropagation()} asChild={true}>
Delete
diff --git a/apps/remix/app/components/tables/settings-security-passkey-table.tsx b/apps/remix/app/components/tables/settings-security-passkey-table.tsx
index b2fe09621..33b566956 100644
--- a/apps/remix/app/components/tables/settings-security-passkey-table.tsx
+++ b/apps/remix/app/components/tables/settings-security-passkey-table.tsx
@@ -1,10 +1,3 @@
-import { useMemo } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { DateTime } from 'luxon';
-import { useLocation, useNavigate, useSearchParams } from 'react-router';
-
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { ZUrlSearchParamsSchema } from '@documenso/lib/types/search-params';
import { trpc } from '@documenso/trpc/react';
@@ -13,6 +6,11 @@ import { DataTable } from '@documenso/ui/primitives/data-table';
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { TableCell } from '@documenso/ui/primitives/table';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { DateTime } from 'luxon';
+import { useMemo } from 'react';
+import { useLocation, useNavigate, useSearchParams } from 'react-router';
import { SettingsSecurityPasskeyTableActions } from './settings-security-passkey-table-actions';
@@ -66,9 +64,7 @@ export const SettingsSecurityPasskeyTable = () => {
header: _(msg`Last used`),
accessorKey: 'updatedAt',
cell: ({ row }) =>
- row.original.lastUsedAt
- ? DateTime.fromJSDate(row.original.lastUsedAt).toRelative()
- : _(msg`Never`),
+ row.original.lastUsedAt ? DateTime.fromJSDate(row.original.lastUsedAt).toRelative() : _(msg`Never`),
},
{
id: 'actions',
diff --git a/apps/remix/app/components/tables/team-groups-table.tsx b/apps/remix/app/components/tables/team-groups-table.tsx
index 3bbf072b4..4ad463cbf 100644
--- a/apps/remix/app/components/tables/team-groups-table.tsx
+++ b/apps/remix/app/components/tables/team-groups-table.tsx
@@ -1,12 +1,3 @@
-import { useMemo } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import { OrganisationGroupType } from '@prisma/client';
-import { EditIcon, MoreHorizontalIcon, Trash2Icon } from 'lucide-react';
-import { useSearchParams } from 'react-router';
-
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { EXTENDED_TEAM_MEMBER_ROLE_MAP } from '@documenso/lib/constants/teams-translations';
import { ZUrlSearchParamsSchema } from '@documenso/lib/types/search-params';
@@ -23,6 +14,13 @@ import {
} from '@documenso/ui/primitives/dropdown-menu';
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { TableCell } from '@documenso/ui/primitives/table';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { OrganisationGroupType } from '@prisma/client';
+import { EditIcon, MoreHorizontalIcon, Trash2Icon } from 'lucide-react';
+import { useMemo } from 'react';
+import { useSearchParams } from 'react-router';
import { useCurrentTeam } from '~/providers/team';
@@ -86,7 +84,7 @@ export const TeamGroupsTable = () => {
cell: ({ row }) => (
-
+
@@ -99,10 +97,7 @@ export const TeamGroupsTable = () => {
teamGroupName={row.original.name ?? ''}
teamGroupRole={row.original.teamRole}
trigger={
- e.preventDefault()}
- title="Update team group role"
- >
+ e.preventDefault()} title="Update team group role">
Update role
@@ -139,7 +134,7 @@ export const TeamGroupsTable = () => {
enable: isLoadingError,
}}
emptyState={
-
+
No team groups found
@@ -173,11 +168,7 @@ export const TeamGroupsTable = () => {
),
}}
>
- {(table) =>
- results.totalPages > 1 && (
-
- )
- }
+ {(table) => results.totalPages > 1 &&
}
);
};
diff --git a/apps/remix/app/components/tables/team-members-table.tsx b/apps/remix/app/components/tables/team-members-table.tsx
index 02771c322..c8a9f0faa 100644
--- a/apps/remix/app/components/tables/team-members-table.tsx
+++ b/apps/remix/app/components/tables/team-members-table.tsx
@@ -1,12 +1,3 @@
-import { useMemo } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import { OrganisationGroupType, OrganisationMemberRole } from '@prisma/client';
-import { EditIcon, MoreHorizontal, Trash2Icon } from 'lucide-react';
-import { useSearchParams } from 'react-router';
-
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
import { EXTENDED_TEAM_MEMBER_ROLE_MAP } from '@documenso/lib/constants/teams-translations';
@@ -28,6 +19,13 @@ import {
} from '@documenso/ui/primitives/dropdown-menu';
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { TableCell } from '@documenso/ui/primitives/table';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { OrganisationGroupType, OrganisationMemberRole } from '@prisma/client';
+import { EditIcon, MoreHorizontal, Trash2Icon } from 'lucide-react';
+import { useMemo } from 'react';
+import { useSearchParams } from 'react-router';
import { useCurrentTeam } from '~/providers/team';
@@ -100,9 +98,7 @@ export const TeamMembersTable = () => {
{row.original.name}
- }
+ primaryText={{row.original.name} }
secondaryText={row.original.email}
/>
);
@@ -130,7 +126,7 @@ export const TeamMembersTable = () => {
cell: ({ row }) => (
-
+
@@ -231,9 +227,7 @@ export const TeamMembersTable = () => {
- {!groupQuery.isPending && (
-
- )}
+ {!groupQuery.isPending && }
);
diff --git a/apps/remix/app/components/tables/templates-table-action-dropdown.tsx b/apps/remix/app/components/tables/templates-table-action-dropdown.tsx
index beaf80a2d..8872a1a78 100644
--- a/apps/remix/app/components/tables/templates-table-action-dropdown.tsx
+++ b/apps/remix/app/components/tables/templates-table-action-dropdown.tsx
@@ -1,24 +1,3 @@
-import { useState } from 'react';
-
-import { Trans } from '@lingui/react/macro';
-import {
- DocumentStatus,
- EnvelopeType,
- type Recipient,
- type TemplateDirectLink,
-} from '@prisma/client';
-import {
- Copy,
- Edit,
- FolderIcon,
- MoreHorizontal,
- Pencil,
- Share2Icon,
- Trash2,
- Upload,
-} from 'lucide-react';
-import { Link } from 'react-router';
-
import type { TRecipientLite } from '@documenso/lib/types/recipient';
import { trpc as trpcReact } from '@documenso/trpc/react';
import {
@@ -28,8 +7,14 @@ import {
DropdownMenuLabel,
DropdownMenuTrigger,
} from '@documenso/ui/primitives/dropdown-menu';
+import { Trans } from '@lingui/react/macro';
+import { DocumentStatus, EnvelopeType, type TemplateDirectLink } from '@prisma/client';
+import { Copy, Download, Edit, FolderIcon, MoreHorizontal, Pencil, Share2Icon, Trash2, Upload } from 'lucide-react';
+import { useState } from 'react';
+import { Link } from 'react-router';
import { EnvelopeDeleteDialog } from '../dialogs/envelope-delete-dialog';
+import { EnvelopeDownloadDialog } from '../dialogs/envelope-download-dialog';
import { EnvelopeDuplicateDialog } from '../dialogs/envelope-duplicate-dialog';
import { EnvelopeRenameDialog } from '../dialogs/envelope-rename-dialog';
import { TemplateBulkSendDialog } from '../dialogs/template-bulk-send-dialog';
@@ -77,87 +62,94 @@ export const TemplatesTableActionDropdown = ({
Action
-
-
-
- Edit
-
-
-
- {canMutate && (
- setRenameDialogOpen(true)}>
-
- Rename
-
- )}
-
- {canMutate && (
- e.preventDefault()}>
-
-
- Duplicate
-
-
- }
- />
- )}
-
- {canMutate && (
-
-
- Direct link
+ e.preventDefault()}>
+
+
+ Download
- }
- />
- )}
-
- setMoveToFolderDialogOpen(true)}>
-
- Move to Folder
-
+
+ }
+ />
{canMutate && (
-
-
- Bulk Send via CSV
-
- }
- />
- )}
+ <>
+
+
+
+ Edit
+
+
- {canMutate && (
- e.preventDefault()}>
-
-
-
Delete
+
setRenameDialogOpen(true)}>
+
+ Rename
+
+
+
e.preventDefault()}>
+
+
+ Duplicate
+
+
+ }
+ />
+
+
+
+ Direct link
-
- }
- />
+ }
+ />
+
+ setMoveToFolderDialogOpen(true)}>
+
+ Move to Folder
+
+
+
+
+ Bulk Send via CSV
+
+ }
+ />
+
+
e.preventDefault()}>
+
+
+ Delete
+
+
+ }
+ />
+ >
)}
diff --git a/apps/remix/app/components/tables/templates-table.tsx b/apps/remix/app/components/tables/templates-table.tsx
index 46240d4ca..cc7754ffd 100644
--- a/apps/remix/app/components/tables/templates-table.tsx
+++ b/apps/remix/app/components/tables/templates-table.tsx
@@ -1,19 +1,3 @@
-import { useMemo, useTransition } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import {
- AlertTriangle,
- Building2Icon,
- Globe2Icon,
- InfoIcon,
- Link2Icon,
- Loader,
- LockIcon,
-} from 'lucide-react';
-import { Link } from 'react-router';
-
import { useLimits } from '@documenso/ee/server-only/limits/provider/client';
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
@@ -27,6 +11,12 @@ import { DataTablePagination } from '@documenso/ui/primitives/data-table-paginat
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { TableCell } from '@documenso/ui/primitives/table';
import { Tooltip, TooltipContent, TooltipTrigger } from '@documenso/ui/primitives/tooltip';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { AlertTriangle, Building2Icon, Globe2Icon, InfoIcon, Link2Icon, Loader, LockIcon } from 'lucide-react';
+import { useMemo, useTransition } from 'react';
+import { Link } from 'react-router';
import { TemplateType } from '~/components/general/template/template-type';
import { useCurrentTeam } from '~/providers/team';
@@ -128,7 +118,7 @@ export const TemplatesTable = ({
-
+
@@ -138,8 +128,8 @@ export const TemplatesTable = ({
- Public templates are connected to your public profile. Any modifications to
- public templates will also appear in your public profile.
+ Public templates are connected to your public profile. Any modifications to public templates
+ will also appear in your public profile.
@@ -151,9 +141,8 @@ export const TemplatesTable = ({
- Direct link templates contain one dynamic recipient placeholder. Anyone with
- access to this link can sign the document, and it will then appear on your
- documents page.
+ Direct link templates contain one dynamic recipient placeholder. Anyone with access to this link
+ can sign the document, and it will then appear on your documents page.
@@ -165,10 +154,7 @@ export const TemplatesTable = ({
{team?.id ? (
-
- Team only templates are not linked anywhere and are visible only to your
- team.
-
+ Team only templates are not linked anywhere and are visible only to your team.
) : (
Private templates can only be modified and viewed by you.
)}
@@ -182,8 +168,8 @@ export const TemplatesTable = ({
- Organisation templates are shared across all teams within the same
- organisation. Only the owning team can edit them.
+ Organisation templates are shared across all teams within the same organisation. Only the owning
+ team can edit them.
@@ -201,9 +187,7 @@ export const TemplatesTable = ({
{isFromOtherTeam && row.original.team?.name && (
-
- ({row.original.team.name})
-
+ ({row.original.team.name})
)}
{row.original.directLink?.token && (
@@ -232,11 +216,7 @@ export const TemplatesTable = ({
documentRootPath={documentRootPath}
/>
-
+
);
},
@@ -273,10 +253,7 @@ export const TemplatesTable = ({
You have reached your document limit.{' '}
-
+
Upgrade your account to continue!
diff --git a/apps/remix/app/components/tables/user-billing-organisations-table.tsx b/apps/remix/app/components/tables/user-billing-organisations-table.tsx
index bc6a2c604..9cf3aebfc 100644
--- a/apps/remix/app/components/tables/user-billing-organisations-table.tsx
+++ b/apps/remix/app/components/tables/user-billing-organisations-table.tsx
@@ -1,10 +1,3 @@
-import { useMemo } from 'react';
-
-import { Trans, useLingui } from '@lingui/react/macro';
-import { SubscriptionStatus } from '@prisma/client';
-import { Link } from 'react-router';
-import { match } from 'ts-pattern';
-
import { useSession } from '@documenso/lib/client-only/providers/session';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { formatAvatarUrl } from '@documenso/lib/utils/avatars';
@@ -14,15 +7,18 @@ import { Badge } from '@documenso/ui/primitives/badge';
import { Button } from '@documenso/ui/primitives/button';
import type { DataTableColumnDef } from '@documenso/ui/primitives/data-table';
import { DataTable } from '@documenso/ui/primitives/data-table';
+import { Trans, useLingui } from '@lingui/react/macro';
+import { SubscriptionStatus } from '@prisma/client';
+import { useMemo } from 'react';
+import { Link } from 'react-router';
+import { match } from 'ts-pattern';
export const UserBillingOrganisationsTable = () => {
const { t } = useLingui();
const { organisations } = useSession();
const billingOrganisations = useMemo(() => {
- return organisations.filter((org) =>
- canExecuteOrganisationAction('MANAGE_BILLING', org.currentOrganisationRole),
- );
+ return organisations.filter((org) => canExecuteOrganisationAction('MANAGE_BILLING', org.currentOrganisationRole));
}, [organisations]);
const getSubscriptionStatusDisplay = (status: SubscriptionStatus | undefined) => {
@@ -56,9 +52,7 @@ export const UserBillingOrganisationsTable = () => {
avatarSrc={formatAvatarUrl(row.original.avatarImageId)}
avatarClass="h-12 w-12"
avatarFallback={row.original.name.slice(0, 1).toUpperCase()}
- primaryText={
- {row.original.name}
- }
+ primaryText={{row.original.name} }
secondaryText={`${NEXT_PUBLIC_WEBAPP_URL()}/o/${row.original.url}`}
/>
@@ -91,7 +85,7 @@ export const UserBillingOrganisationsTable = () => {
if (billingOrganisations.length === 0) {
return (
-
+
You don't manage billing for any organisations.
diff --git a/apps/remix/app/components/tables/user-organisations-table.tsx b/apps/remix/app/components/tables/user-organisations-table.tsx
index 6bfdedadc..ca1131a81 100644
--- a/apps/remix/app/components/tables/user-organisations-table.tsx
+++ b/apps/remix/app/components/tables/user-organisations-table.tsx
@@ -1,10 +1,3 @@
-import { useMemo } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import { Link } from 'react-router';
-
import { useSession } from '@documenso/lib/client-only/providers/session';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { ORGANISATION_MEMBER_ROLE_MAP } from '@documenso/lib/constants/organisations-translations';
@@ -17,6 +10,11 @@ import type { DataTableColumnDef } from '@documenso/ui/primitives/data-table';
import { DataTable } from '@documenso/ui/primitives/data-table';
import { Skeleton } from '@documenso/ui/primitives/skeleton';
import { TableCell } from '@documenso/ui/primitives/table';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { useMemo } from 'react';
+import { Link } from 'react-router';
import { OrganisationLeaveDialog } from '../dialogs/organisation-leave-dialog';
@@ -55,7 +53,7 @@ export const UserOrganisationsTable = () => {
avatarClass="h-12 w-12"
avatarFallback={row.original.name.slice(0, 1).toUpperCase()}
primaryText={
-
+
{isPersonalLayoutMode
? _(
msg({
@@ -92,10 +90,7 @@ export const UserOrganisationsTable = () => {
id: 'actions',
cell: ({ row }) => (
- {canExecuteOrganisationAction(
- 'MANAGE_ORGANISATION',
- row.original.currentOrganisationRole,
- ) && (
+ {canExecuteOrganisationAction('MANAGE_ORGANISATION', row.original.currentOrganisationRole) && (
Manage
diff --git a/apps/remix/app/entry.client.tsx b/apps/remix/app/entry.client.tsx
index c32cdc4e1..86e949d7a 100644
--- a/apps/remix/app/entry.client.tsx
+++ b/apps/remix/app/entry.client.tsx
@@ -1,15 +1,12 @@
-import { StrictMode, startTransition, useEffect } from 'react';
-
+import { extractPostHogConfig } from '@documenso/lib/constants/feature-flags';
+import { dynamicActivate } from '@documenso/lib/utils/i18n';
import { i18n } from '@lingui/core';
import { detect, fromHtmlTag } from '@lingui/detect-locale';
import { I18nProvider } from '@lingui/react';
-import posthog from 'posthog-js';
+import { StrictMode, startTransition, useEffect } from 'react';
import { hydrateRoot } from 'react-dom/client';
import { HydratedRouter } from 'react-router/dom';
-import { extractPostHogConfig } from '@documenso/lib/constants/feature-flags';
-import { dynamicActivate } from '@documenso/lib/utils/i18n';
-
import './utils/polyfills/promise-with-resolvers';
function PosthogInit() {
@@ -17,9 +14,11 @@ function PosthogInit() {
useEffect(() => {
if (postHogConfig) {
- posthog.init(postHogConfig.key, {
- api_host: postHogConfig.host,
- capture_exceptions: true,
+ void import('posthog-js').then(({ default: posthog }) => {
+ posthog.init(postHogConfig.key, {
+ api_host: postHogConfig.host,
+ capture_exceptions: true,
+ });
});
}
}, []);
diff --git a/apps/remix/app/entry.server.tsx b/apps/remix/app/entry.server.tsx
index 6caeba746..7f28001f4 100644
--- a/apps/remix/app/entry.server.tsx
+++ b/apps/remix/app/entry.server.tsx
@@ -1,16 +1,15 @@
+import { PassThrough } from 'node:stream';
+import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n';
+import { dynamicActivate, extractLocaleData } from '@documenso/lib/utils/i18n';
import { i18n } from '@lingui/core';
import { I18nProvider } from '@lingui/react';
import { createReadableStreamFromReadable } from '@react-router/node';
import { isbot } from 'isbot';
-import { PassThrough } from 'node:stream';
import type { RenderToPipeableStreamOptions } from 'react-dom/server';
import { renderToPipeableStream } from 'react-dom/server';
import type { AppLoadContext, EntryContext } from 'react-router';
import { ServerRouter } from 'react-router';
-import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n';
-import { dynamicActivate, extractLocaleData } from '@documenso/lib/utils/i18n';
-
import { langCookie } from './storage/lang-cookie.server';
export const streamTimeout = 5_000;
@@ -20,7 +19,7 @@ export default async function handleRequest(
responseStatusCode: number,
responseHeaders: Headers,
routerContext: EntryContext,
- _loadContext: AppLoadContext,
+ loadContext: AppLoadContext,
) {
let language = await langCookie.parse(request.headers.get('cookie') ?? '');
@@ -30,6 +29,12 @@ export default async function handleRequest(
await dynamicActivate(language);
+ // Threaded into ServerRouter so React Router applies the nonce to the
+ // scripts it injects (route manifest, hydration data, module preloads).
+ // The same nonce is also exposed to the React tree via the root loader so
+ // our own inline scripts/styles can carry it.
+ const nonce = loadContext.nonce || undefined;
+
return new Promise((resolve, reject) => {
let shellRendered = false;
const userAgent = request.headers.get('user-agent');
@@ -41,9 +46,10 @@ export default async function handleRequest(
const { pipe, abort } = renderToPipeableStream(
-
+
,
{
+ nonce,
[readyOption]() {
shellRendered = true;
const body = new PassThrough();
diff --git a/apps/remix/app/providers/team.tsx b/apps/remix/app/providers/team.tsx
index d77c77428..7f309fdbd 100644
--- a/apps/remix/app/providers/team.tsx
+++ b/apps/remix/app/providers/team.tsx
@@ -1,7 +1,6 @@
-import { createContext, useContext } from 'react';
-import React from 'react';
-
import type { TeamSession } from '@documenso/trpc/server/organisation-router/get-organisation-session.types';
+import type React from 'react';
+import { createContext, useContext } from 'react';
type TeamProviderValue = TeamSession;
diff --git a/apps/remix/app/root.tsx b/apps/remix/app/root.tsx
index 47ebf0262..096b1504e 100644
--- a/apps/remix/app/root.tsx
+++ b/apps/remix/app/root.tsx
@@ -1,16 +1,3 @@
-import { NuqsAdapter } from 'nuqs/adapters/react-router/v7';
-import {
- Links,
- Meta,
- Outlet,
- Scripts,
- ScrollRestoration,
- data,
- isRouteErrorResponse,
- useLoaderData,
-} from 'react-router';
-import { PreventFlashOnWrongTheme, ThemeProvider, useTheme } from 'remix-themes';
-
import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session';
import { SessionProvider } from '@documenso/lib/client-only/providers/session';
import { APP_I18N_OPTIONS, type SupportedLanguageCodes } from '@documenso/lib/constants/i18n';
@@ -20,6 +7,19 @@ import { TrpcProvider } from '@documenso/trpc/react';
import { getOrganisationSession } from '@documenso/trpc/server/organisation-router/get-organisation-session';
import { Toaster } from '@documenso/ui/primitives/toaster';
import { TooltipProvider } from '@documenso/ui/primitives/tooltip';
+import { NuqsAdapter } from 'nuqs/adapters/react-router/v7';
+import {
+ data,
+ isRouteErrorResponse,
+ Links,
+ Meta,
+ Outlet,
+ Scripts,
+ ScrollRestoration,
+ useLoaderData,
+ useMatches,
+} from 'react-router';
+import { PreventFlashOnWrongTheme, ThemeProvider, useTheme } from 'remix-themes';
import type { Route } from './+types/root';
import stylesheet from './app.css?url';
@@ -27,6 +27,7 @@ import { GenericErrorLayout } from './components/general/generic-error-layout';
import { langCookie } from './storage/lang-cookie.server';
import { themeSessionResolver } from './storage/theme-session.server';
import { appMetaTags } from './utils/meta';
+import { nonce } from './utils/nonce';
export const links: Route.LinksFunction = () => [{ rel: 'stylesheet', href: stylesheet }];
@@ -41,7 +42,7 @@ export function meta() {
*/
export const shouldRevalidate = () => false;
-export async function loader({ request }: Route.LoaderArgs) {
+export async function loader({ context, request }: Route.LoaderArgs) {
const session = await getOptionalSession(request);
const { getTheme } = await themeSessionResolver(request);
@@ -67,6 +68,10 @@ export async function loader({ request }: Route.LoaderArgs) {
lang,
theme: getTheme(),
disableAnimations,
+ // Surface the per-request CSP nonce produced by `securityHeadersMiddleware` so all
+ // SSR-rendered
+
-
+
{/* Global license banner currently disabled. Need to wait until after a few releases. */}
{/* {licenseStatus === '?' && (
@@ -152,13 +171,14 @@ export function LayoutContent({ children }: { children: React.ReactNode }) {
-
-
+
+
);
diff --git a/apps/remix/app/routes/_authenticated+/_layout.tsx b/apps/remix/app/routes/_authenticated+/_layout.tsx
index 543e61a07..3e53010da 100644
--- a/apps/remix/app/routes/_authenticated+/_layout.tsx
+++ b/apps/remix/app/routes/_authenticated+/_layout.tsx
@@ -1,7 +1,3 @@
-import { msg } from '@lingui/core/macro';
-import { Trans } from '@lingui/react/macro';
-import { Link, Outlet, redirect } from 'react-router';
-
import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session';
import { OrganisationProvider } from '@documenso/lib/client-only/providers/organisation';
import { useSession } from '@documenso/lib/client-only/providers/session';
@@ -9,6 +5,9 @@ import { getSiteSettings } from '@documenso/lib/server-only/site-settings/get-si
import { SITE_SETTINGS_BANNER_ID } from '@documenso/lib/server-only/site-settings/schemas/banner';
import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button';
+import { msg } from '@lingui/core/macro';
+import { Trans } from '@lingui/react/macro';
+import { Link, Outlet, redirect } from 'react-router';
import { AppBanner } from '~/components/general/app-banner';
import { Header } from '~/components/general/app-header';
@@ -29,9 +28,7 @@ export const shouldRevalidate = () => false;
export async function loader({ request }: Route.LoaderArgs) {
const [session, banner] = await Promise.all([
getOptionalSession(request),
- getSiteSettings().then((settings) =>
- settings.find((setting) => setting.id === SITE_SETTINGS_BANNER_ID),
- ),
+ getSiteSettings().then((settings) => settings.find((setting) => setting.id === SITE_SETTINGS_BANNER_ID)),
]);
if (!session.isAuthenticated) {
diff --git a/apps/remix/app/routes/_authenticated+/admin+/_layout.tsx b/apps/remix/app/routes/_authenticated+/admin+/_layout.tsx
index c874b4c92..af24ab0bf 100644
--- a/apps/remix/app/routes/_authenticated+/admin+/_layout.tsx
+++ b/apps/remix/app/routes/_authenticated+/admin+/_layout.tsx
@@ -1,3 +1,8 @@
+import { getSession } from '@documenso/auth/server/lib/utils/get-session';
+import { LicenseClient } from '@documenso/lib/server-only/license/license-client';
+import { isAdmin } from '@documenso/lib/utils/is-admin';
+import { cn } from '@documenso/ui/lib/utils';
+import { Button } from '@documenso/ui/primitives/button';
import { msg } from '@lingui/core/macro';
import { Trans } from '@lingui/react/macro';
import {
@@ -13,12 +18,6 @@ import {
} from 'lucide-react';
import { Link, Outlet, redirect, useLocation } from 'react-router';
-import { getSession } from '@documenso/auth/server/lib/utils/get-session';
-import { LicenseClient } from '@documenso/lib/server-only/license/license-client';
-import { isAdmin } from '@documenso/lib/utils/is-admin';
-import { cn } from '@documenso/ui/lib/utils';
-import { Button } from '@documenso/ui/primitives/button';
-
import { AdminLicenseStatusBanner } from '~/components/general/admin-license-status-banner';
import { appMetaTags } from '~/utils/meta';
@@ -50,7 +49,7 @@ export default function AdminLayout({ loaderData }: Route.ComponentProps) {
-
+
Admin Panel
@@ -62,10 +61,7 @@ export default function AdminLayout({ loaderData }: Route.ComponentProps) {
>
@@ -76,10 +72,7 @@ export default function AdminLayout({ loaderData }: Route.ComponentProps) {
@@ -90,10 +83,7 @@ export default function AdminLayout({ loaderData }: Route.ComponentProps) {
@@ -104,10 +94,7 @@ export default function AdminLayout({ loaderData }: Route.ComponentProps) {
@@ -118,10 +105,7 @@ export default function AdminLayout({ loaderData }: Route.ComponentProps) {
@@ -146,10 +130,7 @@ export default function AdminLayout({ loaderData }: Route.ComponentProps) {
@@ -174,10 +155,7 @@ export default function AdminLayout({ loaderData }: Route.ComponentProps) {
diff --git a/apps/remix/app/routes/_authenticated+/admin+/claims.tsx b/apps/remix/app/routes/_authenticated+/admin+/claims.tsx
index 2028116cb..2122b9077 100644
--- a/apps/remix/app/routes/_authenticated+/admin+/claims.tsx
+++ b/apps/remix/app/routes/_authenticated+/admin+/claims.tsx
@@ -1,11 +1,9 @@
-import { useEffect, useState } from 'react';
-
-import { useLingui } from '@lingui/react/macro';
-import { useLocation, useSearchParams } from 'react-router';
-
import { useDebouncedValue } from '@documenso/lib/client-only/hooks/use-debounced-value';
import { LicenseClient } from '@documenso/lib/server-only/license/license-client';
import { Input } from '@documenso/ui/primitives/input';
+import { useLingui } from '@lingui/react/macro';
+import { useEffect, useState } from 'react';
+import { useLocation, useSearchParams } from 'react-router';
import { ClaimCreateDialog } from '~/components/dialogs/claim-create-dialog';
import { SettingsHeader } from '~/components/general/settings-header';
@@ -55,11 +53,7 @@ export default function Claims({ loaderData }: Route.ComponentProps) {
return (
-
+
diff --git a/apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx b/apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx
index 3aa9282b0..48324bfa3 100644
--- a/apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx
+++ b/apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx
@@ -1,3 +1,14 @@
+import { downloadFile } from '@documenso/lib/client-only/download-file';
+import { unsafeGetEntireEnvelope } from '@documenso/lib/server-only/admin/get-entire-document';
+import { base64 } from '@documenso/lib/universal/base64';
+import { mapSecondaryIdToDocumentId } from '@documenso/lib/utils/envelope';
+import { trpc } from '@documenso/trpc/react';
+import { LocalTime } from '@documenso/ui/components/common/local-time';
+import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@documenso/ui/primitives/accordion';
+import { Badge } from '@documenso/ui/primitives/badge';
+import { Button } from '@documenso/ui/primitives/button';
+import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@documenso/ui/primitives/tooltip';
+import { useToast } from '@documenso/ui/primitives/use-toast';
import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react';
import { Trans } from '@lingui/react/macro';
@@ -6,28 +17,6 @@ import { DownloadIcon } from 'lucide-react';
import { DateTime } from 'luxon';
import { Link, redirect } from 'react-router';
-import { downloadFile } from '@documenso/lib/client-only/download-file';
-import { unsafeGetEntireEnvelope } from '@documenso/lib/server-only/admin/get-entire-document';
-import { base64 } from '@documenso/lib/universal/base64';
-import { mapSecondaryIdToDocumentId } from '@documenso/lib/utils/envelope';
-import { trpc } from '@documenso/trpc/react';
-import { LocalTime } from '@documenso/ui/components/common/local-time';
-import {
- Accordion,
- AccordionContent,
- AccordionItem,
- AccordionTrigger,
-} from '@documenso/ui/primitives/accordion';
-import { Badge } from '@documenso/ui/primitives/badge';
-import { Button } from '@documenso/ui/primitives/button';
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from '@documenso/ui/primitives/tooltip';
-import { useToast } from '@documenso/ui/primitives/use-toast';
-
import { AdminDocumentDeleteDialog } from '~/components/dialogs/admin-document-delete-dialog';
import { DocumentStatus } from '~/components/general/document/document-status';
import { AdminDocumentJobsTable } from '~/components/tables/admin-document-jobs-table';
@@ -60,22 +49,21 @@ export default function AdminDocumentDetailsPage({ loaderData }: Route.Component
const { _, i18n } = useLingui();
const { toast } = useToast();
- const { mutate: resealDocument, isPending: isResealDocumentLoading } =
- trpc.admin.document.reseal.useMutation({
- onSuccess: () => {
- toast({
- title: _(msg`Sealing job started`),
- description: _(msg`See the background jobs tab for the status`),
- });
- },
- onError: () => {
- toast({
- title: _(msg`Error`),
- description: _(msg`Failed to reseal document`),
- variant: 'destructive',
- });
- },
- });
+ const { mutate: resealDocument, isPending: isResealDocumentLoading } = trpc.admin.document.reseal.useMutation({
+ onSuccess: () => {
+ toast({
+ title: _(msg`Sealing job started`),
+ description: _(msg`See the background jobs tab for the status`),
+ });
+ },
+ onError: () => {
+ toast({
+ title: _(msg`Error`),
+ description: _(msg`Failed to reseal document`),
+ variant: 'destructive',
+ });
+ },
+ });
const { mutateAsync: downloadAuditLogs, isPending: isDownloadAuditLogsLoading } =
trpc.admin.document.downloadAuditLogs.useMutation();
@@ -106,7 +94,7 @@ export default function AdminDocumentDetailsPage({ loaderData }: Route.Component
-
{envelope.title}
+ {envelope.title}
@@ -117,7 +105,7 @@ export default function AdminDocumentDetailsPage({ loaderData }: Route.Component
)}
-
+
Document ID : {mapSecondaryIdToDocumentId(envelope.secondaryId)}
@@ -133,7 +121,7 @@ export default function AdminDocumentDetailsPage({ loaderData }: Route.Component
-
+
Admin Actions
@@ -158,8 +146,8 @@ export default function AdminDocumentDetailsPage({ loaderData }: Route.Component
- Attempts sealing the document again, useful for after a code change has occurred to
- resolve an erroneous document.
+ Attempts sealing the document again, useful for after a code change has occurred to resolve an erroneous
+ document.
@@ -173,18 +161,14 @@ export default function AdminDocumentDetailsPage({ loaderData }: Route.Component
-
+
Recipients
{envelope.recipients.map((recipient) => (
-
+
{recipient.name}
@@ -224,9 +208,7 @@ export default function AdminDocumentDetailsPage({ loaderData }: Route.Component
Completed At
-
- {recipient.signedAt ? : '-'}
-
+
{recipient.signedAt ? : '-'}
@@ -248,15 +230,11 @@ export default function AdminDocumentDetailsPage({ loaderData }: Route.Component
-
+
Audit Logs
- void onDownloadAuditLogsClick()}
- >
+ void onDownloadAuditLogsClick()}>
{!isDownloadAuditLogsLoading && }
Download Audit Logs
@@ -265,7 +243,7 @@ export default function AdminDocumentDetailsPage({ loaderData }: Route.Component
-
+
View Audit Logs
diff --git a/apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx b/apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx
index d7bc18be8..30fdca4da 100644
--- a/apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx
+++ b/apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx
@@ -1,11 +1,3 @@
-import { useMemo, useState } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import { Loader } from 'lucide-react';
-import { Link, useSearchParams } from 'react-router';
-
import { useDebouncedValue } from '@documenso/lib/client-only/hooks/use-debounced-value';
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { extractInitials } from '@documenso/lib/utils/recipient-formatter';
@@ -16,6 +8,12 @@ import { DataTable } from '@documenso/ui/primitives/data-table';
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
import { Input } from '@documenso/ui/primitives/input';
import { Tooltip, TooltipContent, TooltipTrigger } from '@documenso/ui/primitives/tooltip';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { Loader } from 'lucide-react';
+import { useMemo, useState } from 'react';
+import { Link, useSearchParams } from 'react-router';
import { DocumentStatus } from '~/components/general/document/document-status';
@@ -32,17 +30,16 @@ export default function AdminDocumentsPage() {
const page = searchParams?.get?.('page') ? Number(searchParams.get('page')) : undefined;
const perPage = searchParams?.get?.('perPage') ? Number(searchParams.get('perPage')) : undefined;
- const { data: findDocumentsData, isPending: isFindDocumentsLoading } =
- trpc.admin.document.find.useQuery(
- {
- query: debouncedTerm,
- page: page || 1,
- perPage: perPage || 20,
- },
- {
- placeholderData: (previousData) => previousData,
- },
- );
+ const { data: findDocumentsData, isPending: isFindDocumentsLoading } = trpc.admin.document.find.useQuery(
+ {
+ query: debouncedTerm,
+ page: page || 1,
+ perPage: perPage || 20,
+ },
+ {
+ placeholderData: (previousData) => previousData,
+ },
+ );
const results = findDocumentsData ?? {
data: [],
@@ -89,22 +86,18 @@ export default function AdminDocumentsPage() {
-
-
- {avatarFallbackText}
-
+
+ {avatarFallbackText}
-
-
- {avatarFallbackText}
-
+
+ {avatarFallbackText}
-
+
{row.original.user.name}
{row.original.user.email}
@@ -130,7 +123,7 @@ export default function AdminDocumentsPage() {
return (
-
+
Manage documents
@@ -152,9 +145,7 @@ export default function AdminDocumentsPage() {
totalPages={results.totalPages ?? 1}
onPaginationChange={onPaginationChange}
>
- {(table) => (
-
- )}
+ {(table) => }
{isFindDocumentsLoading && (
diff --git a/apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx b/apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx
index 442a809b6..bd6ae2a58 100644
--- a/apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx
+++ b/apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx
@@ -1,14 +1,3 @@
-import { useMemo } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import { EmailDomainStatus } from '@prisma/client';
-import { CheckCircle2Icon, ClockIcon, CopyIcon, RotateCcwIcon } from 'lucide-react';
-import { DateTime } from 'luxon';
-import { Link, redirect } from 'react-router';
-import { match } from 'ts-pattern';
-
import { generateEmailDomainRecords } from '@documenso/lib/utils/email-domains';
import { trpc } from '@documenso/trpc/react';
import {
@@ -27,6 +16,15 @@ import { Button } from '@documenso/ui/primitives/button';
import type { DataTableColumnDef } from '@documenso/ui/primitives/data-table';
import { DataTable } from '@documenso/ui/primitives/data-table';
import { useToast } from '@documenso/ui/primitives/use-toast';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { EmailDomainStatus } from '@prisma/client';
+import { CheckCircle2Icon, ClockIcon, CopyIcon, RotateCcwIcon } from 'lucide-react';
+import { DateTime } from 'luxon';
+import { useMemo } from 'react';
+import { Link, redirect } from 'react-router';
+import { match } from 'ts-pattern';
import type { Route } from './+types/email-domains.$id';
@@ -46,32 +44,27 @@ export default function AdminEmailDomainDetailPage({ loaderData }: Route.Compone
const { _, i18n } = useLingui();
const { toast } = useToast();
- const {
- data: emailDomain,
- isPending: isLoading,
- refetch,
- } = trpc.admin.emailDomain.get.useQuery({ emailDomainId });
+ const { data: emailDomain, isPending: isLoading, refetch } = trpc.admin.emailDomain.get.useQuery({ emailDomainId });
- const { mutate: reregisterDomain, isPending: isReregistering } =
- trpc.admin.emailDomain.reregister.useMutation({
- onSuccess: () => {
- toast({
- title: _(msg`Domain re-registered`),
- description: _(
- msg`The SES identity has been deleted and recreated with the same keys. DNS records remain unchanged.`,
- ),
- });
+ const { mutate: reregisterDomain, isPending: isReregistering } = trpc.admin.emailDomain.reregister.useMutation({
+ onSuccess: () => {
+ toast({
+ title: _(msg`Domain re-registered`),
+ description: _(
+ msg`The SES identity has been deleted and recreated with the same keys. DNS records remain unchanged.`,
+ ),
+ });
- void refetch();
- },
- onError: () => {
- toast({
- title: _(msg`Error`),
- description: _(msg`Failed to re-register email domain`),
- variant: 'destructive',
- });
- },
- });
+ void refetch();
+ },
+ onError: () => {
+ toast({
+ title: _(msg`Error`),
+ description: _(msg`Failed to re-register email domain`),
+ variant: 'destructive',
+ });
+ },
+ });
const dnsRecords = useMemo(() => {
if (!emailDomain) {
@@ -110,7 +103,7 @@ export default function AdminEmailDomainDetailPage({ loaderData }: Route.Compone
if (isLoading || !emailDomain) {
return (
-
+
Email Domain
@@ -129,7 +122,7 @@ export default function AdminEmailDomainDetailPage({ loaderData }: Route.Compone
-
{emailDomain.domain}
+ {emailDomain.domain}
{match(emailDomain.status)
.with(EmailDomainStatus.ACTIVE, () => (
@@ -148,16 +141,13 @@ export default function AdminEmailDomainDetailPage({ loaderData }: Route.Compone
-
+
ID : {emailDomain.id}
Organisation :{' '}
-
+
{emailDomain.organisation.name}
@@ -169,9 +159,7 @@ export default function AdminEmailDomainDetailPage({ loaderData }: Route.Compone
Last Verified :{' '}
- {emailDomain.lastVerifiedAt
- ? i18n.date(emailDomain.lastVerifiedAt, DateTime.DATETIME_MED)
- : '-'}
+ {emailDomain.lastVerifiedAt ? i18n.date(emailDomain.lastVerifiedAt, DateTime.DATETIME_MED) : '-'}
{pendingDuration && (
@@ -182,7 +170,7 @@ export default function AdminEmailDomainDetailPage({ loaderData }: Route.Compone
-
+
Admin Actions
@@ -203,10 +191,9 @@ export default function AdminEmailDomainDetailPage({ loaderData }: Route.Compone
- This will delete the existing SES identity for{' '}
- {emailDomain.domain} and recreate it using the same DKIM keys.
- The user will not need to update their DNS records. The domain status will be
- reset to Pending.
+ This will delete the existing SES identity for {emailDomain.domain} and recreate it
+ using the same DKIM keys. The user will not need to update their DNS records. The domain status will
+ be reset to Pending.
@@ -216,9 +203,7 @@ export default function AdminEmailDomainDetailPage({ loaderData }: Route.Compone
Cancel
- reregisterDomain({ emailDomainId: emailDomain.id })}
- >
+ reregisterDomain({ emailDomainId: emailDomain.id })}>
Re-register
@@ -228,7 +213,7 @@ export default function AdminEmailDomainDetailPage({ loaderData }: Route.Compone
-
+
DNS Records
@@ -236,15 +221,11 @@ export default function AdminEmailDomainDetailPage({ loaderData }: Route.Compone
{dnsRecords.map((record, index) => (
-
+
{record.type} Record
-
void onCopyToClipboard(record.value)}
- >
+ void onCopyToClipboard(record.value)}>
Copy Value
@@ -270,7 +251,7 @@ export default function AdminEmailDomainDetailPage({ loaderData }: Route.Compone
-
+
Emails ({emailDomain.emails.length})
@@ -285,7 +266,7 @@ export default function AdminEmailDomainDetailPage({ loaderData }: Route.Compone
onPaginationChange={() => {}}
/>
) : (
-
+
No emails configured for this domain.
)}
diff --git a/apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx b/apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx
index 669747e6d..055620128 100644
--- a/apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx
+++ b/apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx
@@ -1,13 +1,3 @@
-import { useMemo, useState } from 'react';
-
-import { msg } from '@lingui/core/macro';
-import { useLingui } from '@lingui/react';
-import { Trans } from '@lingui/react/macro';
-import { EmailDomainStatus } from '@prisma/client';
-import { CheckCircle2Icon, ClockIcon, Loader } from 'lucide-react';
-import { Link, useSearchParams } from 'react-router';
-import { match } from 'ts-pattern';
-
import { useDebouncedValue } from '@documenso/lib/client-only/hooks/use-debounced-value';
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { trpc } from '@documenso/trpc/react';
@@ -17,13 +7,15 @@ import type { DataTableColumnDef } from '@documenso/ui/primitives/data-table';
import { DataTable } from '@documenso/ui/primitives/data-table';
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
import { Input } from '@documenso/ui/primitives/input';
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from '@documenso/ui/primitives/select';
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@documenso/ui/primitives/select';
+import { msg } from '@lingui/core/macro';
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import { EmailDomainStatus } from '@prisma/client';
+import { CheckCircle2Icon, ClockIcon, Loader } from 'lucide-react';
+import { useMemo, useState } from 'react';
+import { Link, useSearchParams } from 'react-router';
+import { match } from 'ts-pattern';
export default function AdminEmailDomainsPage() {
const { _, i18n } = useLingui();
@@ -38,21 +30,19 @@ export default function AdminEmailDomainsPage() {
const perPage = searchParams?.get?.('perPage') ? Number(searchParams.get('perPage')) : undefined;
const statusParam = searchParams?.get?.('status') ?? 'ALL';
- const statusFilter =
- statusParam === 'PENDING' || statusParam === 'ACTIVE' ? statusParam : undefined;
+ const statusFilter = statusParam === 'PENDING' || statusParam === 'ACTIVE' ? statusParam : undefined;
- const { data: findEmailDomainsData, isPending: isFindEmailDomainsLoading } =
- trpc.admin.emailDomain.find.useQuery(
- {
- query: debouncedTerm,
- page: page || 1,
- perPage: perPage || 20,
- status: statusFilter,
- },
- {
- placeholderData: (previousData) => previousData,
- },
- );
+ const { data: findEmailDomainsData, isPending: isFindEmailDomainsLoading } = trpc.admin.emailDomain.find.useQuery(
+ {
+ query: debouncedTerm,
+ page: page || 1,
+ perPage: perPage || 20,
+ status: statusFilter,
+ },
+ {
+ placeholderData: (previousData) => previousData,
+ },
+ );
const results = findEmailDomainsData ?? {
data: [],
@@ -79,10 +69,7 @@ export default function AdminEmailDomainsPage() {
header: _(msg`Organisation`),
accessorKey: 'organisation',
cell: ({ row }) => (
-
+
{row.original.organisation.name}
),
@@ -119,8 +106,7 @@ export default function AdminEmailDomainsPage() {
{
header: _(msg`Last Verified`),
accessorKey: 'lastVerifiedAt',
- cell: ({ row }) =>
- row.original.lastVerifiedAt ? i18n.date(row.original.lastVerifiedAt) : '-',
+ cell: ({ row }) => (row.original.lastVerifiedAt ? i18n.date(row.original.lastVerifiedAt) : '-'),
},
{
header: _(msg`Actions`),
@@ -151,7 +137,7 @@ export default function AdminEmailDomainsPage() {
return (
-
+
Email Domains
diff --git a/apps/remix/app/routes/_authenticated+/admin+/organisation-insights.$id.tsx b/apps/remix/app/routes/_authenticated+/admin+/organisation-insights.$id.tsx
index 7fb0b1f24..2b92e02f9 100644
--- a/apps/remix/app/routes/_authenticated+/admin+/organisation-insights.$id.tsx
+++ b/apps/remix/app/routes/_authenticated+/admin+/organisation-insights.$id.tsx
@@ -1,10 +1,9 @@
-import { Trans } from '@lingui/react/macro';
-import { Link } from 'react-router';
-
import { getOrganisationDetailedInsights } from '@documenso/lib/server-only/admin/get-organisation-detailed-insights';
import type { DateRange } from '@documenso/lib/types/search-params';
import { getAdminOrganisation } from '@documenso/trpc/server/admin-router/get-admin-organisation';
import { Button } from '@documenso/ui/primitives/button';
+import { Trans } from '@lingui/react/macro';
+import { Link } from 'react-router';
import { OrganisationInsightsTable } from '~/components/tables/organisation-insights-table';
@@ -47,7 +46,7 @@ export default function OrganisationInsights({ loaderData }: Route.ComponentProp
return (
-
{organisationName}
+
{organisationName}
Manage organisation
diff --git a/apps/remix/app/routes/_authenticated+/admin+/organisation-insights._index.tsx b/apps/remix/app/routes/_authenticated+/admin+/organisation-insights._index.tsx
index 1e8783599..1577cbc24 100644
--- a/apps/remix/app/routes/_authenticated+/admin+/organisation-insights._index.tsx
+++ b/apps/remix/app/routes/_authenticated+/admin+/organisation-insights._index.tsx
@@ -1,7 +1,6 @@
-import { Trans } from '@lingui/react/macro';
-
import { getOrganisationInsights } from '@documenso/lib/server-only/admin/get-signing-volume';
import type { DateRange } from '@documenso/lib/types/search-params';
+import { Trans } from '@lingui/react/macro';
import { DateRangeFilter } from '~/components/filters/date-range-filter';
import {
@@ -17,15 +16,12 @@ export async function loader({ request }: Route.LoaderArgs) {
const rawSortBy = url.searchParams.get('sortBy') || 'signingVolume';
const rawSortOrder = url.searchParams.get('sortOrder') || 'desc';
- const isSortOrder = (value: string): value is 'asc' | 'desc' =>
- value === 'asc' || value === 'desc';
+ const isSortOrder = (value: string): value is 'asc' | 'desc' => value === 'asc' || value === 'desc';
const isSortBy = (value: string): value is 'name' | 'createdAt' | 'signingVolume' =>
value === 'name' || value === 'createdAt' || value === 'signingVolume';
const sortOrder: 'asc' | 'desc' = isSortOrder(rawSortOrder) ? rawSortOrder : 'desc';
- const sortBy: 'name' | 'createdAt' | 'signingVolume' = isSortBy(rawSortBy)
- ? rawSortBy
- : 'signingVolume';
+ const sortBy: 'name' | 'createdAt' | 'signingVolume' = isSortBy(rawSortBy) ? rawSortBy : 'signingVolume';
const page = Number(url.searchParams.get('page')) || 1;
const perPage = Number(url.searchParams.get('perPage')) || 10;
@@ -69,7 +65,7 @@ export default function Organisations({ loaderData }: Route.ComponentProps) {
return (
-
+
Organisation Insights
diff --git a/apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx b/apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx
index f3fc58aae..2885fbd9a 100644
--- a/apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx
+++ b/apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx
@@ -1,15 +1,3 @@
-import { useMemo } from 'react';
-
-import { zodResolver } from '@hookform/resolvers/zod';
-import { msg } from '@lingui/core/macro';
-import { Trans, useLingui } from '@lingui/react/macro';
-import { OrganisationMemberRole } from '@prisma/client';
-import { ExternalLinkIcon, InfoIcon, Loader } from 'lucide-react';
-import { useForm } from 'react-hook-form';
-import { Link, useNavigate } from 'react-router';
-import { match } from 'ts-pattern';
-import type { z } from 'zod';
-
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { SUBSCRIPTION_STATUS_MAP } from '@documenso/lib/constants/billing';
import { AppError } from '@documenso/lib/errors/app-error';
@@ -20,12 +8,7 @@ import { getHighestOrganisationRoleInGroup } from '@documenso/lib/utils/organisa
import { trpc } from '@documenso/trpc/react';
import type { TGetAdminOrganisationResponse } from '@documenso/trpc/server/admin-router/get-admin-organisation.types';
import { ZUpdateAdminOrganisationRequestSchema } from '@documenso/trpc/server/admin-router/update-admin-organisation.types';
-import {
- Accordion,
- AccordionContent,
- AccordionItem,
- AccordionTrigger,
-} from '@documenso/ui/primitives/accordion';
+import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@documenso/ui/primitives/accordion';
import { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert';
import { Badge } from '@documenso/ui/primitives/badge';
import { Button } from '@documenso/ui/primitives/button';
@@ -43,7 +26,18 @@ import {
import { Input } from '@documenso/ui/primitives/input';
import { Tooltip, TooltipContent, TooltipTrigger } from '@documenso/ui/primitives/tooltip';
import { useToast } from '@documenso/ui/primitives/use-toast';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { msg } from '@lingui/core/macro';
+import { Trans, useLingui } from '@lingui/react/macro';
+import { OrganisationMemberRole } from '@prisma/client';
+import { ExternalLinkIcon, InfoIcon, Loader } from 'lucide-react';
+import { useMemo } from 'react';
+import { useForm } from 'react-hook-form';
+import { Link, useNavigate } from 'react-router';
+import { match } from 'ts-pattern';
+import type { z } from 'zod';
+import { AdminOrganisationMemberDeleteDialog } from '~/components/dialogs/admin-organisation-member-delete-dialog';
import { AdminOrganisationMemberUpdateDialog } from '~/components/dialogs/admin-organisation-member-update-dialog';
import { DetailsCard, DetailsValue } from '~/components/general/admin-details';
import { AdminGlobalSettingsSection } from '~/components/general/admin-global-settings-section';
@@ -60,10 +54,7 @@ export async function loader() {
};
}
-export default function OrganisationGroupSettingsPage({
- params,
- loaderData,
-}: Route.ComponentProps) {
+export default function OrganisationGroupSettingsPage({ params, loaderData }: Route.ComponentProps) {
const { licenseFlags } = loaderData;
const { i18n, t } = useLingui();
@@ -73,10 +64,9 @@ export default function OrganisationGroupSettingsPage({
const organisationId = params.id;
- const { data: organisation, isLoading: isLoadingOrganisation } =
- trpc.admin.organisation.get.useQuery({
- organisationId,
- });
+ const { data: organisation, isLoading: isLoadingOrganisation } = trpc.admin.organisation.get.useQuery({
+ organisationId,
+ });
const { mutateAsync: createStripeCustomer, isPending: isCreatingStripeCustomer } =
trpc.admin.stripe.createCustomer.useMutation({
@@ -111,9 +101,7 @@ export default function OrganisationGroupSettingsPage({
{
header: t`Team ID`,
accessorKey: 'id',
- cell: ({ row }) => (
- {row.original.id}
- ),
+ cell: ({ row }) => {row.original.id} ,
},
{
header: t`Team url`,
@@ -125,7 +113,7 @@ export default function OrganisationGroupSettingsPage({
accessorKey: 'createdAt',
cell: ({ row }) => {
return (
-
+
{i18n.date(row.original.createdAt)}
);
@@ -135,21 +123,20 @@ export default function OrganisationGroupSettingsPage({
}, [i18n, t]);
const organisationMembersColumns = useMemo(() => {
+ if (!organisation) {
+ return [];
+ }
+
return [
{
header: t`Member`,
cell: ({ row }) => (
-
+
{row.original.user.name ?? row.original.user.email}
{row.original.user.name && (
-
- {row.original.user.email}
-
+
{row.original.user.email}
)}
),
@@ -157,17 +144,11 @@ export default function OrganisationGroupSettingsPage({
{
header: t`User ID`,
accessorKey: 'userId',
- cell: ({ row }) => (
- {row.original.userId}
- ),
+ cell: ({ row }) => {row.original.userId} ,
},
{
header: t`Role`,
cell: ({ row }) => {
- if (!organisation) {
- return null;
- }
-
const isOwner = row.original.userId === organisation.ownerUserId;
if (isOwner) {
@@ -192,7 +173,7 @@ export default function OrganisationGroupSettingsPage({
accessorKey: 'createdAt',
cell: ({ row }) => {
return (
-
+
{i18n.date(row.original.createdAt)}
);
@@ -201,7 +182,9 @@ export default function OrganisationGroupSettingsPage({
{
header: t`Actions`,
cell: ({ row }) => {
- const isOwner = row.original.userId === organisation?.ownerUserId;
+ const isOwner = row.original.userId === organisation.ownerUserId;
+
+ const memberName = row.original.user.name ?? row.original.user.email;
return (
@@ -215,6 +198,16 @@ export default function OrganisationGroupSettingsPage({
organisationMember={row.original}
isOwner={isOwner}
/>
+
+ {!isOwner && (
+
+ )}
);
},
@@ -255,10 +248,7 @@ export default function OrganisationGroupSettingsPage({
return (
-
+
View insights
@@ -271,10 +261,10 @@ export default function OrganisationGroupSettingsPage({
-
+
Organisation usage
-
+
Current usage against organisation limits.
@@ -293,9 +283,7 @@ export default function OrganisationGroupSettingsPage({
Teams}>
{organisation.teams.length} /{' '}
- {organisation.organisationClaim.teamCount === 0
- ? t`Unlimited`
- : organisation.organisationClaim.teamCount}
+ {organisation.organisationClaim.teamCount === 0 ? t`Unlimited` : organisation.organisationClaim.teamCount}
@@ -306,10 +294,10 @@ export default function OrganisationGroupSettingsPage({
-
+
Global Settings
-
+
Default settings applied to this organisation.
@@ -329,10 +317,7 @@ export default function OrganisationGroupSettingsPage({
className="mt-16"
/>
-
+
Subscription
@@ -340,10 +325,7 @@ export default function OrganisationGroupSettingsPage({
{organisation.subscription ? (
-
- {i18n._(SUBSCRIPTION_STATUS_MAP[organisation.subscription.status])} subscription
- found
-
+ {i18n._(SUBSCRIPTION_STATUS_MAP[organisation.subscription.status])} subscription found
) : (
No subscription found
@@ -397,7 +379,7 @@ export default function OrganisationGroupSettingsPage({
-
+
Organisation Members
@@ -407,7 +389,7 @@ export default function OrganisationGroupSettingsPage({
-
+
Organisation Teams
@@ -420,15 +402,12 @@ export default function OrganisationGroupSettingsPage({
);
}
-const ZUpdateGenericOrganisationDataFormSchema =
- ZUpdateAdminOrganisationRequestSchema.shape.data.pick({
- name: true,
- url: true,
- });
+const ZUpdateGenericOrganisationDataFormSchema = ZUpdateAdminOrganisationRequestSchema.shape.data.pick({
+ name: true,
+ url: true,
+});
-type TUpdateGenericOrganisationDataFormSchema = z.infer<
- typeof ZUpdateGenericOrganisationDataFormSchema
->;
+type TUpdateGenericOrganisationDataFormSchema = z.infer;
type OrganisationAdminFormOptions = {
organisation: TGetAdminOrganisationResponse;
@@ -504,7 +483,7 @@ const GenericOrganisationAdminForm = ({ organisation }: OrganisationAdminFormOpt
{!form.formState.errors.url && (
-
+
{field.value ? (
`${NEXT_PUBLIC_WEBAPP_URL()}/o/${field.value}`
) : (
@@ -609,22 +588,21 @@ const OrganisationAdminForm = ({ organisation, licenseFlags }: OrganisationAdmin
- This is the claim that this organisation was initially created with. Any
- feature flag changes to this claim will be backported into this
- organisation.
+ This is the claim that this organisation was initially created with. Any feature flag changes to
+ this claim will be backported into this organisation.
- For example, if the claim has a new flag "FLAG_1" set to true, then this
- organisation will get that flag added.
+ For example, if the claim has a new flag "FLAG_1" set to true, then this organisation will get
+ that flag added.
- This will ONLY backport feature flags which are set to true, anything
- disabled in the initial claim will not be backported
+ This will ONLY backport feature flags which are set to true, anything disabled in the initial
+ claim will not be backported
@@ -653,7 +631,7 @@ const OrganisationAdminForm = ({ organisation, licenseFlags }: OrganisationAdmin
{`https://dashboard.stripe.com/customers/${field.value}`}
@@ -743,8 +721,7 @@ const OrganisationAdminForm = ({ organisation, licenseFlags }: OrganisationAdmin
{Object.values(SUBSCRIPTION_CLAIM_FEATURE_FLAGS).map(({ key, label, isEnterprise }) => {
- const isRestrictedFeature =
- isEnterprise && !licenseFlags?.[key as keyof TLicenseClaim]; // eslint-disable-line @typescript-eslint/consistent-type-assertions
+ const isRestrictedFeature = isEnterprise && !licenseFlags?.[key as keyof TLicenseClaim]; // eslint-disable-line @typescript-eslint/consistent-type-assertions
return (
{label}
diff --git a/apps/remix/app/routes/_authenticated+/admin+/organisations._index.tsx b/apps/remix/app/routes/_authenticated+/admin+/organisations._index.tsx
index b09d3caae..58847e872 100644
--- a/apps/remix/app/routes/_authenticated+/admin+/organisations._index.tsx
+++ b/apps/remix/app/routes/_authenticated+/admin+/organisations._index.tsx
@@ -1,10 +1,8 @@
-import { useEffect, useState } from 'react';
-
-import { useLingui } from '@lingui/react/macro';
-import { useLocation, useSearchParams } from 'react-router';
-
import { useDebouncedValue } from '@documenso/lib/client-only/hooks/use-debounced-value';
import { Input } from '@documenso/ui/primitives/input';
+import { useLingui } from '@lingui/react/macro';
+import { useEffect, useState } from 'react';
+import { useLocation, useSearchParams } from 'react-router';
import { SettingsHeader } from '~/components/general/settings-header';
import { AdminOrganisationsTable } from '~/components/tables/admin-organisations-table';
@@ -41,11 +39,7 @@ export default function Organisations() {
return (
-
+
-
+
Site Banner
-
+
- The site banner is a message that is shown at the top of the site. It can be used to
- display important information to your users.
+ The site banner is a message that is shown at the top of the site. It can be used to display important
+ information to your users.