Skip to content

Commit afe76cd

Browse files
fix(ModalVerificationCode): keep modal open during signing request
On step 3, signDocument() was self-closing the modal immediately after emitting 'change', causing a jarring UX: the modal disappeared while the signing API call was still in-flight, leaving a spinner on a disappeared dialog. - Remove self-close from signDocument(); parent (Sign.vue) already calls actionHandler.closeModal() on both sync and async signing paths, so the modal closes at the right time after the request completes. - Set loading=true in signDocument() so the dialog stays disabled and shows a spinner while the API call runs. - Add watcher on signStore.errors to reset loading=false when the signing request fails, allowing the user to retry without being stuck. - Async signing path is unaffected: Sign.vue closes the modal before transitioning to the progress screen. Tests added to cover: - signDocument emits change with token and does not emit close - signStore.errors watcher resets loading on failure (both modes) Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent 641bdc1 commit afe76cd

2 files changed

Lines changed: 79 additions & 4 deletions

File tree

src/tests/views/SignPDF/_partials/ModalVerificationCode.spec.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { setActivePinia, createPinia } from 'pinia'
88
import { mount } from '@vue/test-utils'
99
import ModalVerificationCode from '@/views/SignPDF/_partials/ModalVerificationCode.vue'
1010
import { useSignMethodsStore } from '@/store/signMethods.js'
11+
import { useSignStore } from '@/store/sign.js'
1112

1213
// Mock axios
1314
vi.mock('@nextcloud/axios', () => ({
@@ -186,6 +187,49 @@ describe('ModalVerificationCode (email mode)', () => {
186187

187188
expect(wrapper.vm.identityVerified).toBe(false)
188189
})
190+
191+
it('signDocument sets loading=true, emits change with token and does NOT self-close', async () => {
192+
signMethodsStore.settings.emailToken.hasConfirmCode = true
193+
wrapper = mountEmail()
194+
195+
wrapper.vm.token = '123456'
196+
wrapper.vm.identityVerified = true
197+
await wrapper.vm.$nextTick()
198+
199+
wrapper.vm.signDocument()
200+
201+
expect(wrapper.vm.loading).toBe(true)
202+
expect(wrapper.emitted('change')).toBeTruthy()
203+
expect(wrapper.emitted('change')![0]).toEqual(['123456'])
204+
expect(wrapper.emitted('close')).toBeFalsy()
205+
})
206+
207+
it('signStore.errors watcher resets loading when signing fails', async () => {
208+
signMethodsStore.settings.emailToken.hasConfirmCode = true
209+
wrapper = mountEmail()
210+
211+
const signStore = useSignStore()
212+
wrapper.vm.loading = true
213+
214+
signStore.setSigningErrors([{ message: 'Signing failed' }])
215+
await wrapper.vm.$nextTick()
216+
217+
expect(wrapper.vm.loading).toBe(false)
218+
})
219+
220+
it('signStore.errors watcher does NOT reset loading when loading is already false', async () => {
221+
signMethodsStore.settings.emailToken.hasConfirmCode = true
222+
wrapper = mountEmail()
223+
224+
const signStore = useSignStore()
225+
wrapper.vm.loading = false
226+
227+
signStore.setSigningErrors([{ message: 'Signing failed' }])
228+
await wrapper.vm.$nextTick()
229+
230+
// loading was already false, no change expected
231+
expect(wrapper.vm.loading).toBe(false)
232+
})
189233
})
190234

191235
describe('ModalVerificationCode (token mode)', () => {
@@ -370,4 +414,32 @@ describe('ModalVerificationCode (token mode)', () => {
370414
expect(wrapper.vm.token).toBe('')
371415
expect(wrapper.vm.identityVerified).toBe(false)
372416
})
417+
418+
it('signDocument sets loading=true, emits change with token and does NOT self-close', async () => {
419+
wrapper = mountToken({ phoneNumber: '+5511999999999' })
420+
421+
wrapper.vm.tokenRequested = true
422+
wrapper.vm.token = '654321'
423+
wrapper.vm.identityVerified = true
424+
await wrapper.vm.$nextTick()
425+
426+
wrapper.vm.signDocument()
427+
428+
expect(wrapper.vm.loading).toBe(true)
429+
expect(wrapper.emitted('change')).toBeTruthy()
430+
expect(wrapper.emitted('change')![0]).toEqual(['654321'])
431+
expect(wrapper.emitted('close')).toBeFalsy()
432+
})
433+
434+
it('signStore.errors watcher resets loading when signing fails', async () => {
435+
wrapper = mountToken({ phoneNumber: '+5511999999999' })
436+
437+
const signStore = useSignStore()
438+
wrapper.vm.loading = true
439+
440+
signStore.setSigningErrors([{ message: 'Signing failed' }])
441+
await wrapper.vm.$nextTick()
442+
443+
expect(wrapper.vm.loading).toBe(false)
444+
})
373445
})

src/views/SignPDF/_partials/ModalVerificationCode.vue

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@
124124
{{ t('libresign', 'Sign document') }}
125125
</NcButton>
126126
</template>
127-
</NcDialog>
127+
</NcDialog>Step 1
128128
</template>
129129

130130
<script>
@@ -279,6 +279,11 @@ export default {
279279
this.signMethodsStore.setEmailToken(token)
280280
}
281281
},
282+
'signStore.errors'(errors) {
283+
if (errors && errors.length > 0 && this.loading) {
284+
this.loading = false
285+
}
286+
},
282287
},
283288
methods: {
284289
t,
@@ -377,10 +382,8 @@ export default {
377382
this.identityVerified = true
378383
},
379384
signDocument() {
385+
this.loading = true
380386
this.$emit('change', this.token)
381-
this.$nextTick(() => {
382-
this.close()
383-
})
384387
},
385388
close() {
386389
if (this.mode === 'token') {

0 commit comments

Comments
 (0)