diff --git a/apps/remix/app/components/general/document-signing/envelope-signing-provider.tsx b/apps/remix/app/components/general/document-signing/envelope-signing-provider.tsx index 760cfdcaf..6fca5c530 100644 --- a/apps/remix/app/components/general/document-signing/envelope-signing-provider.tsx +++ b/apps/remix/app/components/general/document-signing/envelope-signing-provider.tsx @@ -6,7 +6,7 @@ import type { EnvelopeForSigningResponse } from '@documenso/lib/server-only/enve import type { TRecipientActionAuth } from '@documenso/lib/types/document-auth'; import { isFieldUnsignedAndRequired, isRequiredField } from '@documenso/lib/utils/advanced-fields-helpers'; import { extractFieldInsertionValues } from '@documenso/lib/utils/envelope-signing'; -import { getNextDictatableRecipient } from '@documenso/lib/utils/recipient-groups'; +import { effectiveOrder, getNextDictatableRecipient } from '@documenso/lib/utils/recipient-groups'; import { trpc } from '@documenso/trpc/react'; import type { TSignEnvelopeFieldValue } from '@documenso/trpc/server/envelope-router/sign-envelope-field.types'; import { EnvelopeType, type Field, FieldType, type Recipient, RecipientRole, SigningStatus } from '@prisma/client'; @@ -241,7 +241,7 @@ export const EnvelopeSigningProvider = ({ */ const assistantRecipients = recipient.role === RecipientRole.ASSISTANT - ? envelope.recipients.filter((r) => (r.signingOrder ?? 0) > (recipient.signingOrder ?? 0)) + ? envelope.recipients.filter((r) => effectiveOrder(r) > effectiveOrder(recipient)) : []; /** diff --git a/apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx b/apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx index d35313fd8..49f847532 100644 --- a/apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx +++ b/apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx @@ -93,22 +93,23 @@ const handleV1Loader = async ({ params, request }: Route.LoaderArgs) => { }) : [recipient]; - if ( - document.documentMeta?.signingOrder === DocumentSigningOrder.SEQUENTIAL && - recipient.role !== RecipientRole.ASSISTANT - ) { - const nextPendingRecipient = await getNextPendingRecipient({ - documentId: document.id, - currentRecipientId: recipient.id, - }); + // Dictation eligibility must be decided here, over the FULL recipient list + // — the same computation the completion route enforces. `allRecipients` is + // role-scoped (assistants only see strictly later steps, not their own + // group peers), so deriving it client-side from that list would offer + // dictation the server then silently ignores. + const nextPendingRecipient = + document.documentMeta?.signingOrder === DocumentSigningOrder.SEQUENTIAL + ? await getNextPendingRecipient({ + documentId: document.id, + currentRecipientId: recipient.id, + }) + : null; - if (nextPendingRecipient) { - allRecipients.push({ - ...nextPendingRecipient, - fields: [], - }); - } - } + // Only the identity is needed client-side (dictation flag + prefill). + const nextRecipient = nextPendingRecipient + ? { name: nextPendingRecipient.name, email: nextPendingRecipient.email } + : null; const { derivedRecipientAccessAuth } = extractDocumentAuthMethods({ documentAuth: document.authOptions, @@ -170,6 +171,7 @@ const handleV1Loader = async ({ params, request }: Route.LoaderArgs) => { recipient, recipientWithFields, allRecipients, + nextRecipient, completedFields, recipientSignature, isRecipientsTurn, @@ -414,6 +416,7 @@ const SigningPageV1 = ({ data }: { data: Awaited