@smvtech/x-flux 1.0.13 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -69,6 +69,11 @@ declare enum TA_QC_EXTRACTION_STATUS {
69
69
  FAIL = "FAIL",
70
70
  NA = "NA"
71
71
  }
72
+ declare enum VALIDATION_STATUS {
73
+ PERFECT = "PERFECT",
74
+ FIXABLE = "FIXABLE",
75
+ UNFIXABLE = "UNFIXABLE"
76
+ }
72
77
  declare const QuestionnaireSchema: z.ZodObject<{
73
78
  questionsWithRank: z.ZodArray<z.ZodObject<{
74
79
  id: z.ZodString;
@@ -5319,6 +5324,22 @@ type TUploadProgressEvent = {
5319
5324
  interface UploadProgressEvent extends Partial<ProgressEvent> {
5320
5325
  percent?: number;
5321
5326
  }
5327
+ type ValidationItem = {
5328
+ error_text: string;
5329
+ time_saved: number;
5330
+ validation_name: string;
5331
+ };
5332
+ type ValidationResultGroup = {
5333
+ timeSaved: number;
5334
+ items: ValidationItem[];
5335
+ };
5336
+ type ValidationResult = {
5337
+ status: VALIDATION_STATUS;
5338
+ fixable: ValidationResultGroup;
5339
+ unfixable: ValidationResultGroup;
5340
+ perfect: ValidationResultGroup;
5341
+ totalTimeSaved: number;
5342
+ } | null;
5322
5343
 
5323
5344
  type TEDCFlowContext = {
5324
5345
  orderId: string | null;
@@ -5354,6 +5375,62 @@ declare const formatAnswerFromResponse: (updatedAnswer: TAnswer, orderId: string
5354
5375
  declare const updateApplicantWithAnswer: (applicant: TEDCApplicant, question_id: string, answer: TAnswer, questionnaire: TQuestionnaire) => TEDCApplicant;
5355
5376
  declare const createApplicantData: (traveller: TTraveller, answers: TAnswer[], questionnaire: TQuestionnaire, application: TApplication) => TEDCApplicant | null;
5356
5377
  declare function getSignedUrlFromAsset(docId: string): Promise<string | null>;
5378
+ declare function getDisplayableQuestions(questions: TEDCApplicant["questions"], questionAnswerSources: ANSWER_SOURCE[]): TEDCApplicant["questions"];
5379
+ declare function getDisplayableDocuments(questions: TEDCApplicant["questions"], documentAnswerSources: ANSWER_SOURCE[]): TEDCApplicant["questions"];
5380
+ declare function getValidationErrors(validations?: TAnswer["validations"] | null): ValidationResult;
5381
+ declare function validateApplicantQuestions(applicant: TEDCApplicant, questionAnswerSources: ANSWER_SOURCE[]): Array<{
5382
+ name: string;
5383
+ validationResult: ValidationResult;
5384
+ }>;
5385
+ declare function validateApplicantDocuments(applicant: TEDCApplicant, documentAnswerSources: ANSWER_SOURCE[]): Array<{
5386
+ name: string;
5387
+ validationResult: ValidationResult;
5388
+ }>;
5389
+ declare function validateApplicant(applicant: TEDCApplicant, questionAnswerSources: ANSWER_SOURCE[], documentAnswerSources: ANSWER_SOURCE[]): {
5390
+ isComplete: boolean;
5391
+ questionValidations: Array<{
5392
+ name: string;
5393
+ validationResult: ValidationResult;
5394
+ }>;
5395
+ documentValidations: Array<{
5396
+ name: string;
5397
+ validationResult: ValidationResult;
5398
+ }>;
5399
+ applicantValidations: ValidationResult;
5400
+ };
5401
+ declare function validateAllApplicants(applicants: Record<string, TEDCApplicant> | TEDCApplicant[], questionAnswerSources: ANSWER_SOURCE[], documentAnswerSources: ANSWER_SOURCE[]): {
5402
+ isComplete: boolean;
5403
+ applicantValidations: Array<{
5404
+ applicantId: string;
5405
+ applicantName: string;
5406
+ questionValidations: Array<{
5407
+ name: string;
5408
+ validationResult: ValidationResult;
5409
+ }>;
5410
+ documentValidations: Array<{
5411
+ name: string;
5412
+ validationResult: ValidationResult;
5413
+ }>;
5414
+ applicantValidations: ValidationResult;
5415
+ }>;
5416
+ };
5417
+ declare function validateOrder(order: TVisaOrder | null | undefined, applicants: Record<string, TEDCApplicant> | TEDCApplicant[], questionAnswerSources: ANSWER_SOURCE[], documentAnswerSources: ANSWER_SOURCE[]): {
5418
+ isComplete: boolean;
5419
+ orderValidations: ValidationResult;
5420
+ applicantValidations: Array<{
5421
+ applicantId: string;
5422
+ applicantName: string;
5423
+ questionValidations: Array<{
5424
+ name: string;
5425
+ validationResult: ValidationResult;
5426
+ }>;
5427
+ documentValidations: Array<{
5428
+ name: string;
5429
+ validationResult: ValidationResult;
5430
+ }>;
5431
+ applicantValidations: ValidationResult;
5432
+ }>;
5433
+ };
5357
5434
 
5358
5435
  declare const initializeEDCFlow: (config: EDCConfig) => void;
5359
5436
  declare const EDCFlow: {
@@ -5383,4 +5460,4 @@ declare const EDCFlow: {
5383
5460
  };
5384
5461
  };
5385
5462
 
5386
- export { ANSWER_SOURCE, APPLICATION_STATUS, APPLICATION_TAGS, AnswerSchema, type ApiResponse, ApplicationSchema, DOC_TYPES, type EDCConfig, EDCFlowProvider, INTERNAL_ORDER_TAGS, PROCESSING_BLOCKED_ON_PAYMENT_STATUS, QUESTION_TYPE, QuestionnaireSchema, TA_QC_EXTRACTION_STATUS, type TAddTravellerPayload, type TAnswer, type TEDCApplicant, TIMELINE_STEP, type TQuestionWithAnswer, type TQuestionnaire, type TRenderRule, type TTraveller, type TUpdateAnswerPayload, type TUpdateTravellerPayload, type TUploadProgressEvent, type TVisaOrder, TimelinePaymentStatus, TravellerSchema, type UploadProgressEvent, VISA_TYPE_INTERNAL_TAGS, createAllQuestionsWithAnswers, createApplicantData, EDCFlow as default, filterConditionalQuestions, formatAnswerFromResponse, formatTravellerFromResponse, getSignedUrlFromAsset, getVisibleQuestions, initializeEDCFlow, updateApplicantWithAnswer, useEDCFlow };
5463
+ export { ANSWER_SOURCE, APPLICATION_STATUS, APPLICATION_TAGS, AnswerSchema, type ApiResponse, ApplicationSchema, DOC_TYPES, type EDCConfig, EDCFlowProvider, INTERNAL_ORDER_TAGS, PROCESSING_BLOCKED_ON_PAYMENT_STATUS, QUESTION_TYPE, QuestionnaireSchema, TA_QC_EXTRACTION_STATUS, type TAddTravellerPayload, type TAnswer, type TEDCApplicant, TIMELINE_STEP, type TQuestionWithAnswer, type TQuestionnaire, type TRenderRule, type TTraveller, type TUpdateAnswerPayload, type TUpdateTravellerPayload, type TUploadProgressEvent, type TVisaOrder, TimelinePaymentStatus, TravellerSchema, type UploadProgressEvent, VALIDATION_STATUS, VISA_TYPE_INTERNAL_TAGS, type ValidationItem, type ValidationResult, type ValidationResultGroup, createAllQuestionsWithAnswers, createApplicantData, EDCFlow as default, filterConditionalQuestions, formatAnswerFromResponse, formatTravellerFromResponse, getDisplayableDocuments, getDisplayableQuestions, getSignedUrlFromAsset, getValidationErrors, getVisibleQuestions, initializeEDCFlow, updateApplicantWithAnswer, useEDCFlow, validateAllApplicants, validateApplicant, validateApplicantDocuments, validateApplicantQuestions, validateOrder };
package/dist/index.d.ts CHANGED
@@ -69,6 +69,11 @@ declare enum TA_QC_EXTRACTION_STATUS {
69
69
  FAIL = "FAIL",
70
70
  NA = "NA"
71
71
  }
72
+ declare enum VALIDATION_STATUS {
73
+ PERFECT = "PERFECT",
74
+ FIXABLE = "FIXABLE",
75
+ UNFIXABLE = "UNFIXABLE"
76
+ }
72
77
  declare const QuestionnaireSchema: z.ZodObject<{
73
78
  questionsWithRank: z.ZodArray<z.ZodObject<{
74
79
  id: z.ZodString;
@@ -5319,6 +5324,22 @@ type TUploadProgressEvent = {
5319
5324
  interface UploadProgressEvent extends Partial<ProgressEvent> {
5320
5325
  percent?: number;
5321
5326
  }
5327
+ type ValidationItem = {
5328
+ error_text: string;
5329
+ time_saved: number;
5330
+ validation_name: string;
5331
+ };
5332
+ type ValidationResultGroup = {
5333
+ timeSaved: number;
5334
+ items: ValidationItem[];
5335
+ };
5336
+ type ValidationResult = {
5337
+ status: VALIDATION_STATUS;
5338
+ fixable: ValidationResultGroup;
5339
+ unfixable: ValidationResultGroup;
5340
+ perfect: ValidationResultGroup;
5341
+ totalTimeSaved: number;
5342
+ } | null;
5322
5343
 
5323
5344
  type TEDCFlowContext = {
5324
5345
  orderId: string | null;
@@ -5354,6 +5375,62 @@ declare const formatAnswerFromResponse: (updatedAnswer: TAnswer, orderId: string
5354
5375
  declare const updateApplicantWithAnswer: (applicant: TEDCApplicant, question_id: string, answer: TAnswer, questionnaire: TQuestionnaire) => TEDCApplicant;
5355
5376
  declare const createApplicantData: (traveller: TTraveller, answers: TAnswer[], questionnaire: TQuestionnaire, application: TApplication) => TEDCApplicant | null;
5356
5377
  declare function getSignedUrlFromAsset(docId: string): Promise<string | null>;
5378
+ declare function getDisplayableQuestions(questions: TEDCApplicant["questions"], questionAnswerSources: ANSWER_SOURCE[]): TEDCApplicant["questions"];
5379
+ declare function getDisplayableDocuments(questions: TEDCApplicant["questions"], documentAnswerSources: ANSWER_SOURCE[]): TEDCApplicant["questions"];
5380
+ declare function getValidationErrors(validations?: TAnswer["validations"] | null): ValidationResult;
5381
+ declare function validateApplicantQuestions(applicant: TEDCApplicant, questionAnswerSources: ANSWER_SOURCE[]): Array<{
5382
+ name: string;
5383
+ validationResult: ValidationResult;
5384
+ }>;
5385
+ declare function validateApplicantDocuments(applicant: TEDCApplicant, documentAnswerSources: ANSWER_SOURCE[]): Array<{
5386
+ name: string;
5387
+ validationResult: ValidationResult;
5388
+ }>;
5389
+ declare function validateApplicant(applicant: TEDCApplicant, questionAnswerSources: ANSWER_SOURCE[], documentAnswerSources: ANSWER_SOURCE[]): {
5390
+ isComplete: boolean;
5391
+ questionValidations: Array<{
5392
+ name: string;
5393
+ validationResult: ValidationResult;
5394
+ }>;
5395
+ documentValidations: Array<{
5396
+ name: string;
5397
+ validationResult: ValidationResult;
5398
+ }>;
5399
+ applicantValidations: ValidationResult;
5400
+ };
5401
+ declare function validateAllApplicants(applicants: Record<string, TEDCApplicant> | TEDCApplicant[], questionAnswerSources: ANSWER_SOURCE[], documentAnswerSources: ANSWER_SOURCE[]): {
5402
+ isComplete: boolean;
5403
+ applicantValidations: Array<{
5404
+ applicantId: string;
5405
+ applicantName: string;
5406
+ questionValidations: Array<{
5407
+ name: string;
5408
+ validationResult: ValidationResult;
5409
+ }>;
5410
+ documentValidations: Array<{
5411
+ name: string;
5412
+ validationResult: ValidationResult;
5413
+ }>;
5414
+ applicantValidations: ValidationResult;
5415
+ }>;
5416
+ };
5417
+ declare function validateOrder(order: TVisaOrder | null | undefined, applicants: Record<string, TEDCApplicant> | TEDCApplicant[], questionAnswerSources: ANSWER_SOURCE[], documentAnswerSources: ANSWER_SOURCE[]): {
5418
+ isComplete: boolean;
5419
+ orderValidations: ValidationResult;
5420
+ applicantValidations: Array<{
5421
+ applicantId: string;
5422
+ applicantName: string;
5423
+ questionValidations: Array<{
5424
+ name: string;
5425
+ validationResult: ValidationResult;
5426
+ }>;
5427
+ documentValidations: Array<{
5428
+ name: string;
5429
+ validationResult: ValidationResult;
5430
+ }>;
5431
+ applicantValidations: ValidationResult;
5432
+ }>;
5433
+ };
5357
5434
 
5358
5435
  declare const initializeEDCFlow: (config: EDCConfig) => void;
5359
5436
  declare const EDCFlow: {
@@ -5383,4 +5460,4 @@ declare const EDCFlow: {
5383
5460
  };
5384
5461
  };
5385
5462
 
5386
- export { ANSWER_SOURCE, APPLICATION_STATUS, APPLICATION_TAGS, AnswerSchema, type ApiResponse, ApplicationSchema, DOC_TYPES, type EDCConfig, EDCFlowProvider, INTERNAL_ORDER_TAGS, PROCESSING_BLOCKED_ON_PAYMENT_STATUS, QUESTION_TYPE, QuestionnaireSchema, TA_QC_EXTRACTION_STATUS, type TAddTravellerPayload, type TAnswer, type TEDCApplicant, TIMELINE_STEP, type TQuestionWithAnswer, type TQuestionnaire, type TRenderRule, type TTraveller, type TUpdateAnswerPayload, type TUpdateTravellerPayload, type TUploadProgressEvent, type TVisaOrder, TimelinePaymentStatus, TravellerSchema, type UploadProgressEvent, VISA_TYPE_INTERNAL_TAGS, createAllQuestionsWithAnswers, createApplicantData, EDCFlow as default, filterConditionalQuestions, formatAnswerFromResponse, formatTravellerFromResponse, getSignedUrlFromAsset, getVisibleQuestions, initializeEDCFlow, updateApplicantWithAnswer, useEDCFlow };
5463
+ export { ANSWER_SOURCE, APPLICATION_STATUS, APPLICATION_TAGS, AnswerSchema, type ApiResponse, ApplicationSchema, DOC_TYPES, type EDCConfig, EDCFlowProvider, INTERNAL_ORDER_TAGS, PROCESSING_BLOCKED_ON_PAYMENT_STATUS, QUESTION_TYPE, QuestionnaireSchema, TA_QC_EXTRACTION_STATUS, type TAddTravellerPayload, type TAnswer, type TEDCApplicant, TIMELINE_STEP, type TQuestionWithAnswer, type TQuestionnaire, type TRenderRule, type TTraveller, type TUpdateAnswerPayload, type TUpdateTravellerPayload, type TUploadProgressEvent, type TVisaOrder, TimelinePaymentStatus, TravellerSchema, type UploadProgressEvent, VALIDATION_STATUS, VISA_TYPE_INTERNAL_TAGS, type ValidationItem, type ValidationResult, type ValidationResultGroup, createAllQuestionsWithAnswers, createApplicantData, EDCFlow as default, filterConditionalQuestions, formatAnswerFromResponse, formatTravellerFromResponse, getDisplayableDocuments, getDisplayableQuestions, getSignedUrlFromAsset, getValidationErrors, getVisibleQuestions, initializeEDCFlow, updateApplicantWithAnswer, useEDCFlow, validateAllApplicants, validateApplicant, validateApplicantDocuments, validateApplicantQuestions, validateOrder };
package/dist/index.js CHANGED
@@ -123,6 +123,12 @@ var TA_QC_EXTRACTION_STATUS = /* @__PURE__ */ ((TA_QC_EXTRACTION_STATUS2) => {
123
123
  TA_QC_EXTRACTION_STATUS2["NA"] = "NA";
124
124
  return TA_QC_EXTRACTION_STATUS2;
125
125
  })(TA_QC_EXTRACTION_STATUS || {});
126
+ var VALIDATION_STATUS = /* @__PURE__ */ ((VALIDATION_STATUS2) => {
127
+ VALIDATION_STATUS2["PERFECT"] = "PERFECT";
128
+ VALIDATION_STATUS2["FIXABLE"] = "FIXABLE";
129
+ VALIDATION_STATUS2["UNFIXABLE"] = "UNFIXABLE";
130
+ return VALIDATION_STATUS2;
131
+ })(VALIDATION_STATUS || {});
126
132
  var QuestionnaireSchema = z2__namespace.object({
127
133
  questionsWithRank: z2__namespace.array(z2__namespace.object({ id: z2__namespace.string(), rank: z2__namespace.number() })),
128
134
  questionMap: z2__namespace.record(
@@ -274,6 +280,14 @@ var extractDynamicFieldName = (value) => {
274
280
  const match = value.match(/^\{\{([^}]+)\}\}$/);
275
281
  return match ? match[1].trim() : null;
276
282
  };
283
+ var calculateAgeAtTravelDate = (dateOfBirth, travelStartDate) => {
284
+ if (!dateOfBirth || !travelStartDate) return null;
285
+ const [month, day, year] = dateOfBirth.split("/").map(Number);
286
+ const birthDate = new Date(year, month - 1, day);
287
+ if (!birthDate || isNaN(birthDate.getTime())) return null;
288
+ const age = travelStartDate.getFullYear() - birthDate.getFullYear() - (travelStartDate.getMonth() < birthDate.getMonth() || travelStartDate.getMonth() === birthDate.getMonth() && travelStartDate.getDate() < birthDate.getDate() ? 1 : 0);
289
+ return age;
290
+ };
277
291
  var shouldRenderQuestion = (render, answerValue, application) => {
278
292
  const dynamicFieldName = extractDynamicFieldName(render.value);
279
293
  if (dynamicFieldName) {
@@ -289,6 +303,18 @@ var shouldRenderQuestion = (render, answerValue, application) => {
289
303
  return false;
290
304
  }
291
305
  }
306
+ case "travel_start_date-18_years": {
307
+ const age = calculateAgeAtTravelDate(answerValue[0], /* @__PURE__ */ new Date());
308
+ if (!age) return false;
309
+ switch (render.operation) {
310
+ case "lt":
311
+ return age < 18;
312
+ case "gte":
313
+ return age >= 18;
314
+ default:
315
+ return false;
316
+ }
317
+ }
292
318
  default:
293
319
  return false;
294
320
  }
@@ -436,6 +462,7 @@ async function getSignedUrlFromAsset(docId) {
436
462
  return null;
437
463
  }
438
464
  }
465
+ var getFullName = (firstName, middleName, lastName) => `${firstName || ""} ${middleName || ""} ${lastName || ""}`.replace(/\s\s+/g, " ");
439
466
  var findQuestionsWithDynamicOptions = (questionnaire, dynamicValue) => {
440
467
  return Object.entries(questionnaire.questionMap).filter(([, question]) => question.options?.includes(`{{${dynamicValue}}}`)).map(([id]) => id);
441
468
  };
@@ -520,6 +547,202 @@ var runApplicantSideEffects = (applicants, questionnaire, dynamicQuestionMap) =>
520
547
  const updatedApplicants = updateApplicantsQuestionOptions(applicants, dynamicQuestionMap, updatedQuestionnaire);
521
548
  return { updatedQuestionnaire, updatedApplicants };
522
549
  };
550
+ var extractDefaultAnswer = (value) => {
551
+ const match = value.match(/^\{\{default\}\}$/i);
552
+ return match ? match[0] : null;
553
+ };
554
+ function getDisplayableQuestions(questions, questionAnswerSources) {
555
+ return questions.filter((q) => {
556
+ if (q.question.type === "DOCUMENT" /* DOCUMENT */) return false;
557
+ if (!q.question.is_root) {
558
+ return q.question.answer_source === "USER_INPUT" /* USER_INPUT */;
559
+ }
560
+ return questionAnswerSources.includes(q.question.answer_source);
561
+ });
562
+ }
563
+ function getDisplayableDocuments(questions, documentAnswerSources) {
564
+ return questions.filter(
565
+ (q) => q.question.type === "DOCUMENT" /* DOCUMENT */ && documentAnswerSources.includes(q.question.answer_source)
566
+ );
567
+ }
568
+ var EMPTY_GROUP = { timeSaved: 0, items: [] };
569
+ function toGroup(items) {
570
+ const timeSaved = items.reduce((sum, v) => sum + v.time_saved, 0);
571
+ return { timeSaved, items };
572
+ }
573
+ function getValidationErrors(validations) {
574
+ const fixableItems = [];
575
+ const unfixableItems = [];
576
+ const perfectItems = [];
577
+ if (!validations || !Array.isArray(validations) || validations.length === 0) {
578
+ return {
579
+ status: "PERFECT" /* PERFECT */,
580
+ fixable: EMPTY_GROUP,
581
+ unfixable: EMPTY_GROUP,
582
+ perfect: EMPTY_GROUP,
583
+ totalTimeSaved: 0
584
+ };
585
+ }
586
+ validations.forEach((v) => {
587
+ const item = {
588
+ error_text: v.error_text || "",
589
+ time_saved: v.time_saved || 0,
590
+ validation_name: v.validation_name || ""
591
+ };
592
+ if (v.result === false) {
593
+ if (v.fix_type === "none") {
594
+ unfixableItems.push(item);
595
+ } else {
596
+ fixableItems.push(item);
597
+ }
598
+ } else {
599
+ perfectItems.push(item);
600
+ }
601
+ });
602
+ const fixable = toGroup(fixableItems);
603
+ const unfixable = toGroup(unfixableItems);
604
+ const perfect = toGroup(perfectItems);
605
+ const totalTimeSaved = fixable.timeSaved + unfixable.timeSaved + perfect.timeSaved;
606
+ let status;
607
+ if (unfixable.items.length > 0) {
608
+ status = "UNFIXABLE" /* UNFIXABLE */;
609
+ } else if (fixable.items.length > 0) {
610
+ status = "FIXABLE" /* FIXABLE */;
611
+ } else {
612
+ status = "PERFECT" /* PERFECT */;
613
+ }
614
+ return {
615
+ status,
616
+ fixable,
617
+ unfixable,
618
+ perfect,
619
+ totalTimeSaved
620
+ };
621
+ }
622
+ function getQuestionValidationResult(question) {
623
+ if (question.question.is_required) {
624
+ const isDocument = question.question.type === "DOCUMENT" /* DOCUMENT */;
625
+ let answerRequiredItem = null;
626
+ if (isDocument) {
627
+ const hasApproved = question.answer_data?.assets_id?.find((asset) => asset.status === "APPROVED");
628
+ if (!hasApproved) {
629
+ answerRequiredItem = {
630
+ error_text: "Please upload the required document",
631
+ time_saved: 0,
632
+ validation_name: "answer_required"
633
+ };
634
+ }
635
+ } else {
636
+ const answer = question.answer_data?.answer?.[0];
637
+ if (!answer || answer === "") {
638
+ answerRequiredItem = {
639
+ error_text: "Answer cannot be empty",
640
+ time_saved: 0,
641
+ validation_name: "answer_required"
642
+ };
643
+ } else if (extractDefaultAnswer(answer) !== null) {
644
+ answerRequiredItem = {
645
+ error_text: "Please provide a valid answer",
646
+ time_saved: 0,
647
+ validation_name: "answer_required"
648
+ };
649
+ }
650
+ }
651
+ if (answerRequiredItem) {
652
+ const unfixable = toGroup([answerRequiredItem]);
653
+ return {
654
+ status: "UNFIXABLE" /* UNFIXABLE */,
655
+ fixable: EMPTY_GROUP,
656
+ unfixable,
657
+ perfect: EMPTY_GROUP,
658
+ totalTimeSaved: 0
659
+ };
660
+ }
661
+ }
662
+ const backendResult = getValidationErrors(question.answer_data?.validations);
663
+ return backendResult ?? {
664
+ status: "PERFECT" /* PERFECT */,
665
+ fixable: EMPTY_GROUP,
666
+ unfixable: EMPTY_GROUP,
667
+ perfect: EMPTY_GROUP,
668
+ totalTimeSaved: 0
669
+ };
670
+ }
671
+ function validateApplicantQuestions(applicant, questionAnswerSources) {
672
+ const displayableQuestions = getDisplayableQuestions(applicant.questions, questionAnswerSources);
673
+ const questionValidations = [];
674
+ displayableQuestions.forEach((question) => {
675
+ const validationResult = getQuestionValidationResult(question);
676
+ if (validationResult && validationResult.status === "UNFIXABLE" /* UNFIXABLE */) {
677
+ questionValidations.push({
678
+ name: question.question.question,
679
+ validationResult
680
+ });
681
+ }
682
+ });
683
+ return questionValidations;
684
+ }
685
+ function validateApplicantDocuments(applicant, documentAnswerSources) {
686
+ const displayableDocuments = getDisplayableDocuments(applicant.questions, documentAnswerSources);
687
+ const documentValidations = [];
688
+ displayableDocuments.forEach((document) => {
689
+ const validationResult = getQuestionValidationResult(document);
690
+ if (validationResult && validationResult.status === "UNFIXABLE" /* UNFIXABLE */) {
691
+ documentValidations.push({
692
+ name: document.question.question,
693
+ validationResult
694
+ });
695
+ }
696
+ });
697
+ return documentValidations;
698
+ }
699
+ function validateApplicant(applicant, questionAnswerSources, documentAnswerSources) {
700
+ const questionValidations = validateApplicantQuestions(applicant, questionAnswerSources);
701
+ const documentValidations = validateApplicantDocuments(applicant, documentAnswerSources);
702
+ const applicantValidations = getValidationErrors(applicant.application?.validations);
703
+ const hasUnfixableIssues = questionValidations.some((q) => q.validationResult?.status === "UNFIXABLE" /* UNFIXABLE */) || documentValidations.some((d) => d.validationResult?.status === "UNFIXABLE" /* UNFIXABLE */) || applicantValidations?.status === "UNFIXABLE" /* UNFIXABLE */;
704
+ return {
705
+ isComplete: !hasUnfixableIssues && questionValidations.length === 0 && documentValidations.length === 0,
706
+ questionValidations,
707
+ documentValidations,
708
+ applicantValidations
709
+ };
710
+ }
711
+ function validateAllApplicants(applicants, questionAnswerSources, documentAnswerSources) {
712
+ const applicantsArray = Array.isArray(applicants) ? applicants : Object.values(applicants);
713
+ const applicantValidations = [];
714
+ applicantsArray.forEach((applicant) => {
715
+ const validation = validateApplicant(applicant, questionAnswerSources, documentAnswerSources);
716
+ if (!validation.isComplete) {
717
+ const applicantName = getFullName(
718
+ applicant.traveller.first_name,
719
+ applicant.traveller.middle_name,
720
+ applicant.traveller.last_name
721
+ );
722
+ applicantValidations.push({
723
+ applicantId: applicant.application_id,
724
+ applicantName,
725
+ questionValidations: validation.questionValidations,
726
+ documentValidations: validation.documentValidations,
727
+ applicantValidations: validation.applicantValidations
728
+ });
729
+ }
730
+ });
731
+ return {
732
+ isComplete: applicantValidations.length === 0,
733
+ applicantValidations
734
+ };
735
+ }
736
+ function validateOrder(order, applicants, questionAnswerSources, documentAnswerSources) {
737
+ const orderValidations = getValidationErrors(order?.validations);
738
+ const applicantsResult = validateAllApplicants(applicants, questionAnswerSources, documentAnswerSources);
739
+ const hasOrderUnfixableIssues = orderValidations?.status === "UNFIXABLE" /* UNFIXABLE */;
740
+ return {
741
+ isComplete: !hasOrderUnfixableIssues && applicantsResult.isComplete,
742
+ orderValidations,
743
+ applicantValidations: applicantsResult.applicantValidations
744
+ };
745
+ }
523
746
 
524
747
  // src/api/index.ts
525
748
  var transformApplicationData = (rawData) => {
@@ -874,7 +1097,6 @@ var EDCFlowProvider = ({ children, orderId }) => {
874
1097
  try {
875
1098
  setError(null);
876
1099
  const { data } = await runAllValidations(orderId);
877
- console.log("data", data);
878
1100
  if (data.order) {
879
1101
  setOrder(data.order);
880
1102
  }
@@ -1470,6 +1692,7 @@ exports.TA_QC_EXTRACTION_STATUS = TA_QC_EXTRACTION_STATUS;
1470
1692
  exports.TIMELINE_STEP = TIMELINE_STEP;
1471
1693
  exports.TimelinePaymentStatus = TimelinePaymentStatus;
1472
1694
  exports.TravellerSchema = TravellerSchema;
1695
+ exports.VALIDATION_STATUS = VALIDATION_STATUS;
1473
1696
  exports.VISA_TYPE_INTERNAL_TAGS = VISA_TYPE_INTERNAL_TAGS;
1474
1697
  exports.createAllQuestionsWithAnswers = createAllQuestionsWithAnswers;
1475
1698
  exports.createApplicantData = createApplicantData;
@@ -1477,8 +1700,16 @@ exports.default = index_default;
1477
1700
  exports.filterConditionalQuestions = filterConditionalQuestions;
1478
1701
  exports.formatAnswerFromResponse = formatAnswerFromResponse;
1479
1702
  exports.formatTravellerFromResponse = formatTravellerFromResponse;
1703
+ exports.getDisplayableDocuments = getDisplayableDocuments;
1704
+ exports.getDisplayableQuestions = getDisplayableQuestions;
1480
1705
  exports.getSignedUrlFromAsset = getSignedUrlFromAsset;
1706
+ exports.getValidationErrors = getValidationErrors;
1481
1707
  exports.getVisibleQuestions = getVisibleQuestions;
1482
1708
  exports.initializeEDCFlow = initializeEDCFlow;
1483
1709
  exports.updateApplicantWithAnswer = updateApplicantWithAnswer;
1484
1710
  exports.useEDCFlow = useEDCFlow;
1711
+ exports.validateAllApplicants = validateAllApplicants;
1712
+ exports.validateApplicant = validateApplicant;
1713
+ exports.validateApplicantDocuments = validateApplicantDocuments;
1714
+ exports.validateApplicantQuestions = validateApplicantQuestions;
1715
+ exports.validateOrder = validateOrder;
package/dist/index.mjs CHANGED
@@ -97,6 +97,12 @@ var TA_QC_EXTRACTION_STATUS = /* @__PURE__ */ ((TA_QC_EXTRACTION_STATUS2) => {
97
97
  TA_QC_EXTRACTION_STATUS2["NA"] = "NA";
98
98
  return TA_QC_EXTRACTION_STATUS2;
99
99
  })(TA_QC_EXTRACTION_STATUS || {});
100
+ var VALIDATION_STATUS = /* @__PURE__ */ ((VALIDATION_STATUS2) => {
101
+ VALIDATION_STATUS2["PERFECT"] = "PERFECT";
102
+ VALIDATION_STATUS2["FIXABLE"] = "FIXABLE";
103
+ VALIDATION_STATUS2["UNFIXABLE"] = "UNFIXABLE";
104
+ return VALIDATION_STATUS2;
105
+ })(VALIDATION_STATUS || {});
100
106
  var QuestionnaireSchema = z2.object({
101
107
  questionsWithRank: z2.array(z2.object({ id: z2.string(), rank: z2.number() })),
102
108
  questionMap: z2.record(
@@ -248,6 +254,14 @@ var extractDynamicFieldName = (value) => {
248
254
  const match = value.match(/^\{\{([^}]+)\}\}$/);
249
255
  return match ? match[1].trim() : null;
250
256
  };
257
+ var calculateAgeAtTravelDate = (dateOfBirth, travelStartDate) => {
258
+ if (!dateOfBirth || !travelStartDate) return null;
259
+ const [month, day, year] = dateOfBirth.split("/").map(Number);
260
+ const birthDate = new Date(year, month - 1, day);
261
+ if (!birthDate || isNaN(birthDate.getTime())) return null;
262
+ const age = travelStartDate.getFullYear() - birthDate.getFullYear() - (travelStartDate.getMonth() < birthDate.getMonth() || travelStartDate.getMonth() === birthDate.getMonth() && travelStartDate.getDate() < birthDate.getDate() ? 1 : 0);
263
+ return age;
264
+ };
251
265
  var shouldRenderQuestion = (render, answerValue, application) => {
252
266
  const dynamicFieldName = extractDynamicFieldName(render.value);
253
267
  if (dynamicFieldName) {
@@ -263,6 +277,18 @@ var shouldRenderQuestion = (render, answerValue, application) => {
263
277
  return false;
264
278
  }
265
279
  }
280
+ case "travel_start_date-18_years": {
281
+ const age = calculateAgeAtTravelDate(answerValue[0], /* @__PURE__ */ new Date());
282
+ if (!age) return false;
283
+ switch (render.operation) {
284
+ case "lt":
285
+ return age < 18;
286
+ case "gte":
287
+ return age >= 18;
288
+ default:
289
+ return false;
290
+ }
291
+ }
266
292
  default:
267
293
  return false;
268
294
  }
@@ -410,6 +436,7 @@ async function getSignedUrlFromAsset(docId) {
410
436
  return null;
411
437
  }
412
438
  }
439
+ var getFullName = (firstName, middleName, lastName) => `${firstName || ""} ${middleName || ""} ${lastName || ""}`.replace(/\s\s+/g, " ");
413
440
  var findQuestionsWithDynamicOptions = (questionnaire, dynamicValue) => {
414
441
  return Object.entries(questionnaire.questionMap).filter(([, question]) => question.options?.includes(`{{${dynamicValue}}}`)).map(([id]) => id);
415
442
  };
@@ -494,6 +521,202 @@ var runApplicantSideEffects = (applicants, questionnaire, dynamicQuestionMap) =>
494
521
  const updatedApplicants = updateApplicantsQuestionOptions(applicants, dynamicQuestionMap, updatedQuestionnaire);
495
522
  return { updatedQuestionnaire, updatedApplicants };
496
523
  };
524
+ var extractDefaultAnswer = (value) => {
525
+ const match = value.match(/^\{\{default\}\}$/i);
526
+ return match ? match[0] : null;
527
+ };
528
+ function getDisplayableQuestions(questions, questionAnswerSources) {
529
+ return questions.filter((q) => {
530
+ if (q.question.type === "DOCUMENT" /* DOCUMENT */) return false;
531
+ if (!q.question.is_root) {
532
+ return q.question.answer_source === "USER_INPUT" /* USER_INPUT */;
533
+ }
534
+ return questionAnswerSources.includes(q.question.answer_source);
535
+ });
536
+ }
537
+ function getDisplayableDocuments(questions, documentAnswerSources) {
538
+ return questions.filter(
539
+ (q) => q.question.type === "DOCUMENT" /* DOCUMENT */ && documentAnswerSources.includes(q.question.answer_source)
540
+ );
541
+ }
542
+ var EMPTY_GROUP = { timeSaved: 0, items: [] };
543
+ function toGroup(items) {
544
+ const timeSaved = items.reduce((sum, v) => sum + v.time_saved, 0);
545
+ return { timeSaved, items };
546
+ }
547
+ function getValidationErrors(validations) {
548
+ const fixableItems = [];
549
+ const unfixableItems = [];
550
+ const perfectItems = [];
551
+ if (!validations || !Array.isArray(validations) || validations.length === 0) {
552
+ return {
553
+ status: "PERFECT" /* PERFECT */,
554
+ fixable: EMPTY_GROUP,
555
+ unfixable: EMPTY_GROUP,
556
+ perfect: EMPTY_GROUP,
557
+ totalTimeSaved: 0
558
+ };
559
+ }
560
+ validations.forEach((v) => {
561
+ const item = {
562
+ error_text: v.error_text || "",
563
+ time_saved: v.time_saved || 0,
564
+ validation_name: v.validation_name || ""
565
+ };
566
+ if (v.result === false) {
567
+ if (v.fix_type === "none") {
568
+ unfixableItems.push(item);
569
+ } else {
570
+ fixableItems.push(item);
571
+ }
572
+ } else {
573
+ perfectItems.push(item);
574
+ }
575
+ });
576
+ const fixable = toGroup(fixableItems);
577
+ const unfixable = toGroup(unfixableItems);
578
+ const perfect = toGroup(perfectItems);
579
+ const totalTimeSaved = fixable.timeSaved + unfixable.timeSaved + perfect.timeSaved;
580
+ let status;
581
+ if (unfixable.items.length > 0) {
582
+ status = "UNFIXABLE" /* UNFIXABLE */;
583
+ } else if (fixable.items.length > 0) {
584
+ status = "FIXABLE" /* FIXABLE */;
585
+ } else {
586
+ status = "PERFECT" /* PERFECT */;
587
+ }
588
+ return {
589
+ status,
590
+ fixable,
591
+ unfixable,
592
+ perfect,
593
+ totalTimeSaved
594
+ };
595
+ }
596
+ function getQuestionValidationResult(question) {
597
+ if (question.question.is_required) {
598
+ const isDocument = question.question.type === "DOCUMENT" /* DOCUMENT */;
599
+ let answerRequiredItem = null;
600
+ if (isDocument) {
601
+ const hasApproved = question.answer_data?.assets_id?.find((asset) => asset.status === "APPROVED");
602
+ if (!hasApproved) {
603
+ answerRequiredItem = {
604
+ error_text: "Please upload the required document",
605
+ time_saved: 0,
606
+ validation_name: "answer_required"
607
+ };
608
+ }
609
+ } else {
610
+ const answer = question.answer_data?.answer?.[0];
611
+ if (!answer || answer === "") {
612
+ answerRequiredItem = {
613
+ error_text: "Answer cannot be empty",
614
+ time_saved: 0,
615
+ validation_name: "answer_required"
616
+ };
617
+ } else if (extractDefaultAnswer(answer) !== null) {
618
+ answerRequiredItem = {
619
+ error_text: "Please provide a valid answer",
620
+ time_saved: 0,
621
+ validation_name: "answer_required"
622
+ };
623
+ }
624
+ }
625
+ if (answerRequiredItem) {
626
+ const unfixable = toGroup([answerRequiredItem]);
627
+ return {
628
+ status: "UNFIXABLE" /* UNFIXABLE */,
629
+ fixable: EMPTY_GROUP,
630
+ unfixable,
631
+ perfect: EMPTY_GROUP,
632
+ totalTimeSaved: 0
633
+ };
634
+ }
635
+ }
636
+ const backendResult = getValidationErrors(question.answer_data?.validations);
637
+ return backendResult ?? {
638
+ status: "PERFECT" /* PERFECT */,
639
+ fixable: EMPTY_GROUP,
640
+ unfixable: EMPTY_GROUP,
641
+ perfect: EMPTY_GROUP,
642
+ totalTimeSaved: 0
643
+ };
644
+ }
645
+ function validateApplicantQuestions(applicant, questionAnswerSources) {
646
+ const displayableQuestions = getDisplayableQuestions(applicant.questions, questionAnswerSources);
647
+ const questionValidations = [];
648
+ displayableQuestions.forEach((question) => {
649
+ const validationResult = getQuestionValidationResult(question);
650
+ if (validationResult && validationResult.status === "UNFIXABLE" /* UNFIXABLE */) {
651
+ questionValidations.push({
652
+ name: question.question.question,
653
+ validationResult
654
+ });
655
+ }
656
+ });
657
+ return questionValidations;
658
+ }
659
+ function validateApplicantDocuments(applicant, documentAnswerSources) {
660
+ const displayableDocuments = getDisplayableDocuments(applicant.questions, documentAnswerSources);
661
+ const documentValidations = [];
662
+ displayableDocuments.forEach((document) => {
663
+ const validationResult = getQuestionValidationResult(document);
664
+ if (validationResult && validationResult.status === "UNFIXABLE" /* UNFIXABLE */) {
665
+ documentValidations.push({
666
+ name: document.question.question,
667
+ validationResult
668
+ });
669
+ }
670
+ });
671
+ return documentValidations;
672
+ }
673
+ function validateApplicant(applicant, questionAnswerSources, documentAnswerSources) {
674
+ const questionValidations = validateApplicantQuestions(applicant, questionAnswerSources);
675
+ const documentValidations = validateApplicantDocuments(applicant, documentAnswerSources);
676
+ const applicantValidations = getValidationErrors(applicant.application?.validations);
677
+ const hasUnfixableIssues = questionValidations.some((q) => q.validationResult?.status === "UNFIXABLE" /* UNFIXABLE */) || documentValidations.some((d) => d.validationResult?.status === "UNFIXABLE" /* UNFIXABLE */) || applicantValidations?.status === "UNFIXABLE" /* UNFIXABLE */;
678
+ return {
679
+ isComplete: !hasUnfixableIssues && questionValidations.length === 0 && documentValidations.length === 0,
680
+ questionValidations,
681
+ documentValidations,
682
+ applicantValidations
683
+ };
684
+ }
685
+ function validateAllApplicants(applicants, questionAnswerSources, documentAnswerSources) {
686
+ const applicantsArray = Array.isArray(applicants) ? applicants : Object.values(applicants);
687
+ const applicantValidations = [];
688
+ applicantsArray.forEach((applicant) => {
689
+ const validation = validateApplicant(applicant, questionAnswerSources, documentAnswerSources);
690
+ if (!validation.isComplete) {
691
+ const applicantName = getFullName(
692
+ applicant.traveller.first_name,
693
+ applicant.traveller.middle_name,
694
+ applicant.traveller.last_name
695
+ );
696
+ applicantValidations.push({
697
+ applicantId: applicant.application_id,
698
+ applicantName,
699
+ questionValidations: validation.questionValidations,
700
+ documentValidations: validation.documentValidations,
701
+ applicantValidations: validation.applicantValidations
702
+ });
703
+ }
704
+ });
705
+ return {
706
+ isComplete: applicantValidations.length === 0,
707
+ applicantValidations
708
+ };
709
+ }
710
+ function validateOrder(order, applicants, questionAnswerSources, documentAnswerSources) {
711
+ const orderValidations = getValidationErrors(order?.validations);
712
+ const applicantsResult = validateAllApplicants(applicants, questionAnswerSources, documentAnswerSources);
713
+ const hasOrderUnfixableIssues = orderValidations?.status === "UNFIXABLE" /* UNFIXABLE */;
714
+ return {
715
+ isComplete: !hasOrderUnfixableIssues && applicantsResult.isComplete,
716
+ orderValidations,
717
+ applicantValidations: applicantsResult.applicantValidations
718
+ };
719
+ }
497
720
 
498
721
  // src/api/index.ts
499
722
  var transformApplicationData = (rawData) => {
@@ -848,7 +1071,6 @@ var EDCFlowProvider = ({ children, orderId }) => {
848
1071
  try {
849
1072
  setError(null);
850
1073
  const { data } = await runAllValidations(orderId);
851
- console.log("data", data);
852
1074
  if (data.order) {
853
1075
  setOrder(data.order);
854
1076
  }
@@ -1429,4 +1651,4 @@ var EDCFlow = {
1429
1651
  };
1430
1652
  var index_default = EDCFlow;
1431
1653
 
1432
- export { ANSWER_SOURCE, APPLICATION_STATUS, APPLICATION_TAGS, AnswerSchema, ApplicationSchema, DOC_TYPES, EDCFlowProvider, INTERNAL_ORDER_TAGS, PROCESSING_BLOCKED_ON_PAYMENT_STATUS, QUESTION_TYPE, QuestionnaireSchema, TA_QC_EXTRACTION_STATUS, TIMELINE_STEP, TimelinePaymentStatus, TravellerSchema, VISA_TYPE_INTERNAL_TAGS, createAllQuestionsWithAnswers, createApplicantData, index_default as default, filterConditionalQuestions, formatAnswerFromResponse, formatTravellerFromResponse, getSignedUrlFromAsset, getVisibleQuestions, initializeEDCFlow, updateApplicantWithAnswer, useEDCFlow };
1654
+ export { ANSWER_SOURCE, APPLICATION_STATUS, APPLICATION_TAGS, AnswerSchema, ApplicationSchema, DOC_TYPES, EDCFlowProvider, INTERNAL_ORDER_TAGS, PROCESSING_BLOCKED_ON_PAYMENT_STATUS, QUESTION_TYPE, QuestionnaireSchema, TA_QC_EXTRACTION_STATUS, TIMELINE_STEP, TimelinePaymentStatus, TravellerSchema, VALIDATION_STATUS, VISA_TYPE_INTERNAL_TAGS, createAllQuestionsWithAnswers, createApplicantData, index_default as default, filterConditionalQuestions, formatAnswerFromResponse, formatTravellerFromResponse, getDisplayableDocuments, getDisplayableQuestions, getSignedUrlFromAsset, getValidationErrors, getVisibleQuestions, initializeEDCFlow, updateApplicantWithAnswer, useEDCFlow, validateAllApplicants, validateApplicant, validateApplicantDocuments, validateApplicantQuestions, validateOrder };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smvtech/x-flux",
3
- "version": "1.0.13",
3
+ "version": "1.1.0",
4
4
  "description": "x-flux - A powerful React package for managing effective document collection flows, visa questionnaires, travellers, and applications",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",