|
8 | 8 | <Signatures v-if="hasSignatures" /> |
9 | 9 | </div> |
10 | 10 | <div v-if="!loading" class="button-wrapper"> |
| 11 | + <NcNoteCard v-for="(error, index) in signStore.errors" |
| 12 | + :key="index" |
| 13 | + :heading="error.title || ''" |
| 14 | + type="error"> |
| 15 | + <NcRichText :text="error.message" |
| 16 | + :use-markdown="true" /> |
| 17 | + </NcNoteCard> |
11 | 18 | <div v-if="needCreateSignature" class="no-signature-warning"> |
12 | 19 | <p> |
13 | 20 | {{ t('libresign', 'You do not have any signature defined.') }} |
|
44 | 51 | <div v-else-if="needIdentificationDocuments" class="no-identification-warning"> |
45 | 52 | <Documents :sign-request-uuid="signRequestUuid" /> |
46 | 53 | </div> |
| 54 | + <div v-else-if="hasBlockingSignError" class="sign-blocked-warning"> |
| 55 | + <p> |
| 56 | + <!-- TRANSLATORS Shown after a non-retriable certificate validation failure. "Signing is blocked" means the signer cannot continue now and must resolve the certificate issue first. --> |
| 57 | + {{ t('libresign', 'Signing is blocked until the certificate validation issue is resolved.') }} |
| 58 | + </p> |
| 59 | + <NcButton :wide="true" |
| 60 | + :disabled="loading" |
| 61 | + @click="clearBlockingSignError"> |
| 62 | + {{ t('libresign', 'Try signing again') }} |
| 63 | + </NcButton> |
| 64 | + </div> |
47 | 65 | <NcButton v-else-if="ableToSign" |
48 | 66 | :wide="true" |
49 | 67 | :disabled="loading" |
@@ -283,6 +301,13 @@ defineOptions({ |
283 | 301 | this.actionHandler.showModal(modalCode) |
284 | 302 | } |
285 | 303 |
|
| 304 | + const shouldCloseModal = (methodConfig.modalCode || methodConfig.method || 'token') === 'password' |
| 305 | + && Array.isArray(signError.errors) |
| 306 | + && signError.errors.some((error) => Number(error?.code) === 422) |
| 307 | + if (shouldCloseModal) { |
| 308 | + this.actionHandler.closeModal(methodConfig.modalCode || methodConfig.method || 'token') |
| 309 | + } |
| 310 | +
|
286 | 311 | this.signStore.setSigningErrors(signError.errors || []) |
287 | 312 | } finally { |
288 | 313 | this.loading = false |
@@ -346,6 +371,21 @@ type SignSubmissionError = { |
346 | 371 | errors?: SignError[] |
347 | 372 | } |
348 | 373 |
|
| 374 | +const NON_RETRIABLE_SIGN_ERROR_CODE = 422 |
| 375 | +
|
| 376 | +function shouldCloseCurrentModalOnSignError( |
| 377 | + methodConfig: SignatureMethodConfig, |
| 378 | + signError: SignSubmissionError, |
| 379 | +): boolean { |
| 380 | + const modalCode = methodConfig.modalCode || methodConfig.method || 'token' |
| 381 | + if (modalCode !== 'password') { |
| 382 | + return false |
| 383 | + } |
| 384 | +
|
| 385 | + const errors = Array.isArray(signError.errors) ? signError.errors : [] |
| 386 | + return errors.some((error) => Number(error?.code) === NON_RETRIABLE_SIGN_ERROR_CODE) |
| 387 | +} |
| 388 | +
|
349 | 389 | type SignStoreContract = ReturnType<typeof useSignStore> & { |
350 | 390 | document: SignDocument |
351 | 391 | errors: SignError[] |
@@ -455,6 +495,7 @@ const canCreateSignature = computed(() => { |
455 | 495 | return capabilities.libresign?.config['sign-elements']['can-create-signature'] === true |
456 | 496 | }) |
457 | 497 | const ableToSign = computed(() => signStore.ableToSign) |
| 498 | +const hasBlockingSignError = computed(() => signStore.errors.some((error) => Number(error?.code) === NON_RETRIABLE_SIGN_ERROR_CODE)) |
458 | 499 | const signRequestUuid = computed(() => { |
459 | 500 | const doc = signStore.document |
460 | 501 | const signer = doc?.signers?.find((row) => row.me) ?? doc?.signers?.[0] |
@@ -524,6 +565,10 @@ function onSignatureFileCreated() { |
524 | 565 | showManagePassword.value = false |
525 | 566 | } |
526 | 567 |
|
| 568 | +function clearBlockingSignError() { |
| 569 | + signStore.clearSigningErrors() |
| 570 | +} |
| 571 | +
|
527 | 572 | function saveSignature() { |
528 | 573 | if (signatureElementsStore.success.length) { |
529 | 574 | showSuccess(signatureElementsStore.success) |
@@ -645,6 +690,10 @@ let submitSignature = async (methodConfig: SignatureMethodConfig = {}) => { |
645 | 690 | actionHandler!.showModal(modalCode) |
646 | 691 | } |
647 | 692 |
|
| 693 | + if (shouldCloseCurrentModalOnSignError(methodConfig, signError)) { |
| 694 | + actionHandler!.closeModal(methodConfig.modalCode || methodConfig.method || 'token') |
| 695 | + } |
| 696 | +
|
648 | 697 | signStore.setSigningErrors(signError.errors || []) |
649 | 698 | } finally { |
650 | 699 | loading.value = false |
@@ -793,6 +842,13 @@ defineExpose({ |
793 | 842 | margin-top: 1em; |
794 | 843 | } |
795 | 844 |
|
| 845 | +.sign-blocked-warning { |
| 846 | + margin-top: 1em; |
| 847 | + display: flex; |
| 848 | + flex-direction: column; |
| 849 | + gap: 8px; |
| 850 | +} |
| 851 | +
|
796 | 852 | .button-wrapper { |
797 | 853 | padding: calc(var(--default-grid-baseline, 4px)*2); |
798 | 854 | } |
|
0 commit comments