Skip to content

Commit 3010dc5

Browse files
refactor(validation): slim view by isolating document contracts
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent f258608 commit 3010dc5

1 file changed

Lines changed: 17 additions & 276 deletions

File tree

src/views/Validation.vue

Lines changed: 17 additions & 276 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,14 @@ import { openDocument } from '../utils/viewer.js'
129129
import { getStatusLabel } from '../utils/fileStatus.js'
130130
import { getSigningRouteUuid } from '../utils/signRequestUuid.ts'
131131
import { FILE_STATUS, SIGN_REQUEST_STATUS } from '../constants.js'
132+
import {
133+
isLoadedValidationEnvelopeDocument,
134+
isLoadedValidationFileDocument,
135+
MODIFICATION_ALLOWED,
136+
MODIFICATION_UNMODIFIED,
137+
MODIFICATION_VIOLATION,
138+
toValidationDocument,
139+
} from '../services/validationDocument'
132140
import logger from '../logger.js'
133141
import { useFilesStore } from '../store/files.js'
134142
import { useSignStore } from '../store/sign.js'
@@ -138,6 +146,13 @@ import type {
138146
ValidatedChildFileRecord,
139147
ValidationFileRecord,
140148
} from '../types/index'
149+
import type {
150+
LoadedValidationEnvelopeDocumentState,
151+
LoadedValidationFileDocumentState,
152+
ValidationDocumentState,
153+
ValidationModificationInfo,
154+
ValidationStatusInfo,
155+
} from '../services/validationDocument'
141156
142157
defineOptions({
143158
name: 'Validation',
@@ -161,25 +176,7 @@ type RouterState = {
161176
}
162177
163178
type ToggleOpenState = Record<number, boolean>
164-
type ValidationStatus = ValidationFileRecord['status']
165-
type ValidationStatusInfo = {
166-
id?: number
167-
label?: string
168-
}
169-
170-
const MODIFICATION_UNMODIFIED = 1
171-
const MODIFICATION_ALLOWED = 2
172-
const MODIFICATION_VIOLATION = 3
173179
174-
type ModificationValidationStatus =
175-
typeof MODIFICATION_UNMODIFIED
176-
| typeof MODIFICATION_ALLOWED
177-
| typeof MODIFICATION_VIOLATION
178-
179-
type ValidationModificationInfo = {
180-
status?: ModificationValidationStatus
181-
valid?: boolean
182-
}
183180
type ValidationDisplaySigner = SignerDetailRecord & {
184181
signature_validation?: ValidationStatusInfo
185182
certificate_validation?: ValidationStatusInfo
@@ -209,41 +206,8 @@ type ValidationErrorResponse = {
209206
}
210207
}
211208
212-
type ValidationMetadataDimension = {
213-
w: number
214-
h: number
215-
}
216-
217-
type ValidationDocumentState = ValidationFileRecord & {
218-
signers: SignerDetailRecord[]
219-
metadata: NonNullable<ValidationFileRecord['metadata']>
220-
settings: NonNullable<ValidationFileRecord['settings']>
221-
}
222-
223-
type LoadedValidationEnvelopeDocumentState = ValidationDocumentState & {
224-
nodeType: 'envelope'
225-
}
226-
227-
type LoadedValidationFileDocumentState = ValidationDocumentState & {
228-
nodeType: 'file'
229-
}
230-
231-
type UnknownRecord = Record<string, unknown>
232-
233-
function isRecord(value: unknown): value is Record<string, unknown> {
234-
return typeof value === 'object' && value !== null
235-
}
236-
237-
function hasOwn(record: UnknownRecord, key: string): boolean {
238-
return Object.prototype.hasOwnProperty.call(record, key)
239-
}
240-
241-
function isOptionalField(record: UnknownRecord, key: string, guard: (value: unknown) => boolean): boolean {
242-
return !hasOwn(record, key) || guard(record[key])
243-
}
244-
245209
function normalizeRouteRecord(value: unknown, source: 'params' | 'query'): Record<string, string> {
246-
if (!isRecord(value)) {
210+
if (typeof value !== 'object' || value === null) {
247211
return {}
248212
}
249213
@@ -271,22 +235,6 @@ function toNumber(value: unknown): number | null {
271235
return typeof value === 'number' && Number.isFinite(value) ? value : null
272236
}
273237
274-
function isValidationStatus(value: unknown): value is ValidationStatus {
275-
const normalizedValue = toNumber(value)
276-
return normalizedValue === FILE_STATUS.DRAFT
277-
|| normalizedValue === FILE_STATUS.ABLE_TO_SIGN
278-
|| normalizedValue === FILE_STATUS.PARTIAL_SIGNED
279-
|| normalizedValue === FILE_STATUS.SIGNED
280-
|| normalizedValue === FILE_STATUS.DELETED
281-
}
282-
283-
function isSignerStatus(value: unknown): value is SignerDetailRecord['status'] {
284-
const normalizedValue = toNumber(value)
285-
return normalizedValue === SIGN_REQUEST_STATUS.DRAFT
286-
|| normalizedValue === SIGN_REQUEST_STATUS.ABLE_TO_SIGN
287-
|| normalizedValue === SIGN_REQUEST_STATUS.SIGNED
288-
}
289-
290238
function isValidationRouteName(value: RouteState['name']): value is ValidationRouteName {
291239
return value === 'validation'
292240
|| value === 'ValidationFile'
@@ -298,220 +246,13 @@ function isSignedDocumentStatus(status: unknown): boolean {
298246
return Number(status) === FILE_STATUS.SIGNED
299247
}
300248
301-
function isString(value: unknown): value is string {
302-
return typeof value === 'string'
303-
}
304-
305-
function isNullableString(value: unknown): value is string | null {
306-
return value === null || typeof value === 'string'
307-
}
308-
309-
function isValidationStatusInfo(value: unknown): value is ValidationStatusInfo {
310-
if (!isRecord(value)) {
311-
return false
312-
}
313-
314-
return isOptionalField(value, 'id', fieldValue => typeof fieldValue === 'number')
315-
&& isOptionalField(value, 'label', isString)
316-
}
317-
318-
function isValidationModificationInfo(value: unknown): value is ValidationModificationInfo {
319-
if (!isRecord(value)) {
320-
return false
321-
}
322-
323-
return isOptionalField(value, 'status', isModificationValidationStatus)
324-
&& isOptionalField(value, 'valid', fieldValue => typeof fieldValue === 'boolean')
325-
}
326-
327-
function isModificationValidationStatus(value: unknown): value is ModificationValidationStatus {
328-
return value === MODIFICATION_UNMODIFIED
329-
|| value === MODIFICATION_ALLOWED
330-
|| value === MODIFICATION_VIOLATION
331-
}
332-
333-
function isValidationMetadataDimension(value: unknown): value is ValidationMetadataDimension {
334-
if (!isRecord(value)) {
335-
return false
336-
}
337-
338-
return typeof value.w === 'number' && Number.isFinite(value.w)
339-
&& typeof value.h === 'number' && Number.isFinite(value.h)
340-
}
341-
342-
function isRequestedBy(value: unknown): value is ValidationFileRecord['requested_by'] {
343-
if (!isRecord(value)) {
344-
return false
345-
}
346-
return isString(value.userId) && isString(value.displayName)
347-
}
348-
349-
function isValidationMetadata(value: unknown): value is NonNullable<ValidationFileRecord['metadata']> {
350-
if (!isRecord(value)) {
351-
return false
352-
}
353-
354-
if (!isString(value.extension) || typeof value.p !== 'number') {
355-
return false
356-
}
357-
358-
return isOptionalField(value, 'd', fieldValue => Array.isArray(fieldValue) && fieldValue.every(isValidationMetadataDimension))
359-
&& isOptionalField(value, 'original_file_deleted', fieldValue => typeof fieldValue === 'boolean')
360-
&& isOptionalField(value, 'pdfVersion', isString)
361-
&& isOptionalField(value, 'status_changed_at', isString)
362-
}
363-
364-
function isValidationSettings(value: unknown): value is NonNullable<ValidationFileRecord['settings']> {
365-
if (!isRecord(value)) {
366-
return false
367-
}
368-
return typeof value.canSign === 'boolean'
369-
&& typeof value.canRequestSign === 'boolean'
370-
&& typeof value.phoneNumber === 'string'
371-
&& typeof value.hasSignatureFile === 'boolean'
372-
&& typeof value.needIdentificationDocuments === 'boolean'
373-
&& typeof value.identificationDocumentsWaitingApproval === 'boolean'
374-
&& isOptionalField(value, 'isApprover', fieldValue => typeof fieldValue === 'boolean')
375-
}
376-
377-
function isSignerDetailRecord(value: unknown): value is SignerDetailRecord {
378-
if (!isRecord(value)) {
379-
return false
380-
}
381-
382-
return typeof value.signRequestId === 'number'
383-
&& isString(value.displayName)
384-
&& isString(value.email)
385-
&& isNullableString(value.signed)
386-
&& isSignerStatus(value.status)
387-
&& isString(value.statusText)
388-
&& isNullableString(value.description)
389-
&& isString(value.request_sign_date)
390-
&& typeof value.me === 'boolean'
391-
&& Array.isArray(value.visibleElements)
392-
&& isOptionalField(value, 'signature_validation', isValidationStatusInfo)
393-
&& isOptionalField(value, 'certificate_validation', isValidationStatusInfo)
394-
&& isOptionalField(value, 'modification_validation', isValidationModificationInfo)
395-
&& isOptionalField(value, 'crl_validation', isString)
396-
&& isOptionalField(value, 'isLibreSignRootCA', fieldValue => typeof fieldValue === 'boolean')
397-
}
398-
399-
function isValidatedChildFileRecord(value: unknown): value is ValidatedChildFileRecord {
400-
if (!isRecord(value)) {
401-
return false
402-
}
403-
404-
return typeof value.id === 'number'
405-
&& isString(value.uuid)
406-
&& isString(value.name)
407-
&& isValidationStatus(value.status)
408-
&& isString(value.statusText)
409-
&& typeof value.nodeId === 'number'
410-
&& typeof value.size === 'number'
411-
&& Array.isArray(value.signers)
412-
&& isString(value.file)
413-
&& isValidationMetadata(value.metadata)
414-
}
415-
416-
function isValidationDocumentRecord(data: unknown): data is ValidationFileRecord {
417-
if (!isRecord(data)) {
418-
return false
419-
}
420-
if (
421-
typeof data.id !== 'number'
422-
|| !isString(data.uuid)
423-
|| !isString(data.name)
424-
|| !isValidationStatus(data.status)
425-
|| !isString(data.statusText)
426-
|| typeof data.nodeId !== 'number'
427-
|| (data.nodeType !== 'file' && data.nodeType !== 'envelope')
428-
|| typeof data.signatureFlow !== 'number'
429-
|| typeof data.docmdpLevel !== 'number'
430-
|| typeof data.filesCount !== 'number'
431-
|| !Array.isArray(data.files)
432-
|| typeof data.totalPages !== 'number'
433-
|| typeof data.size !== 'number'
434-
|| !isString(data.pdfVersion)
435-
|| !isString(data.created_at)
436-
|| !isRequestedBy(data.requested_by)
437-
) {
438-
return false
439-
}
440-
441-
if (!data.files.every(isValidatedChildFileRecord)) {
442-
return false
443-
}
444-
445-
if (hasOwn(data, 'signers') && (!Array.isArray(data.signers) || !data.signers.every(isSignerDetailRecord))) {
446-
return false
447-
}
448-
449-
if (hasOwn(data, 'metadata') && !isValidationMetadata(data.metadata)) {
450-
return false
451-
}
452-
453-
if (hasOwn(data, 'settings') && !isValidationSettings(data.settings)) {
454-
return false
455-
}
456-
457-
return true
458-
}
459-
460-
const DEFAULT_VALIDATION_METADATA: NonNullable<ValidationFileRecord['metadata']> = {
461-
extension: 'pdf',
462-
p: 0,
463-
}
464-
465-
const DEFAULT_VALIDATION_SETTINGS: NonNullable<ValidationFileRecord['settings']> = {
466-
canSign: false,
467-
canRequestSign: false,
468-
phoneNumber: '',
469-
hasSignatureFile: false,
470-
needIdentificationDocuments: false,
471-
identificationDocumentsWaitingApproval: false,
472-
}
473-
474-
function toValidationDocument(data: unknown): ValidationDocumentState | null {
475-
if (!isValidationDocumentRecord(data)) {
476-
return null
477-
}
478-
479-
const metadata = isValidationMetadata(data.metadata)
480-
? data.metadata
481-
: {
482-
...DEFAULT_VALIDATION_METADATA,
483-
p: data.totalPages,
484-
}
485-
486-
const settings = isValidationSettings(data.settings)
487-
? data.settings
488-
: DEFAULT_VALIDATION_SETTINGS
489-
490-
const signers = Array.isArray(data.signers) ? data.signers : []
491-
492-
return {
493-
...data,
494-
metadata,
495-
settings,
496-
signers,
497-
}
498-
}
499-
500249
function getValidationErrorMessage(response: ValidationErrorResponse | undefined, fallback: string): string {
501250
if (response?.data?.ocs?.data?.errors?.length) {
502251
return response.data.ocs.data.errors[0]?.message || fallback
503252
}
504253
return fallback
505254
}
506255
507-
function isLoadedValidationEnvelopeDocument(document: ValidationDocumentState | null): document is LoadedValidationEnvelopeDocumentState {
508-
return document?.nodeType === 'envelope'
509-
}
510-
511-
function isLoadedValidationFileDocument(document: ValidationDocumentState | null): document is LoadedValidationFileDocumentState {
512-
return document?.nodeType === 'file'
513-
}
514-
515256
const signStore = useSignStore()
516257
const sidebarStore = useSidebarStore()
517258
const filesStore = useFilesStore()
@@ -974,7 +715,7 @@ function syncValidatedDocumentToFilesStore(validationDocument: ValidationFileRec
974715
? currentFile.files
975716
: []
976717
if (nestedFiles.length > 0) {
977-
pendingFiles.push(...nestedFiles.filter((file): file is ValidatedChildFileRecord => isRecord(file)))
718+
pendingFiles.push(...nestedFiles.filter((file): file is ValidatedChildFileRecord => typeof file === 'object' && file !== null))
978719
}
979720
}
980721
}

0 commit comments

Comments
 (0)