Files
2026-03-25 11:54:22 -05:00

9.3 KiB

File Upload Component

The file upload component in /src/app/shared/file-upload allows for files to be uploaded to Azure Blob Storage for a given loan. Once the loan is created in ACTion it will upload the files to ACTion and show up in Attachments. An example of the component shown here:

Image alt text

Enabling Employment Income/Other Income file uploads for a loan

Set showProofOfIncomeUploadForm value for the loan to true in src\app\shared\loan-type.ts

Adding the upload component to a form (see end of document for an example implementation)

  1. Update interface by adding two variables: files and isUploading, example in src\app\loan-wizard\field-groups\personal\personal-information.ts
  2. Add new values to form group in src\app\loan-wizard\field-groups\common-groups.ts, see PERSONAL_INFO in this file for an example
  3. Add the HTML to the form, example below and in src\app\loan-wizard\field-groups\personal\personal-info-form.component.html
  4. Update TS by adding variables needed, example below and in src\app\loan-wizard\field-groups\personal\personal-info-form.component.ts
  5. Update src\assets\i18n\en.json to have verbiage for uploading document
  6. Update src\app\shared\loan-type.ts to set beforeYouBeginKey value on a given loan to the corresponding key in en.json to enable the checklist
  7. Update the summary component to show files if they're present, example in src\app\loan-wizard\wizards\common\summary\personal-summary.component.html

Inputs

  1. loanId required
    • The CosmosDB loan ID that uploaded files will be associated with
  2. section optional
    • The section that the form is in, e.g. Collateral.
    • If left blank, the description in ACTion will not include this.
  3. sectionId required
    • The sectionId is used to be more specific, when there are multiple upload components in a single form.
    • An example would be the Income section that shows up to 3 upload components for any borrower on the loan, for which the sectionId is set to Primary Borrower-#, where # would be which income section it is associated with, 1, 2, or 3.
  4. description required
    • Description that is used to set the attachment type in ACTion
    • This text will be displayed in the component after "Upload"
    • This text can be overridden by passing a value in for the label input
  5. label optional
    • This text will be displayed in the component after "Upload"
    • This was added in after the verbiage requirements needed something more custom in certain areas to show something like Upload a copy of first mortgage balance statement instead of Upload Copy of first mortgage balance statement.
    • If label is not provided, description will be shown.
  6. removeAllFilesSubject optional
    • This input is used by passing in a Subject<boolean> and then triggered by calling the .next() function on the subject, which will remove all files and emit when completed.
    • It is meant to be used along with the removedAllFiles output to notify the parent component that the files have been removed and the form can be updated.

Outputs

  1. sendFiles required
    • Used to capture when files change and need to be updated on the parent component.
  2. uploadingFiles required
    • Used for form validation so that the Next button cannot be pressed while a file is being uploaded or deleted.
  3. removedAllFiles optional
    • Used when a form is closed/not needed and the files that were uploaded need to be deleted.
    • Once removedAllFilesSubject is called and completed, this output is emitted so that the form can be updated as needed.

Notes

  • When the component loads, it creates two requests for the API: one for the files associated with the loanId and the other for the settings, which controls the file size and types.
  • The <lw-file-upload> component should be surround with a div that controls the width and visibility, e.g.:
<div *ngIf="showUploadForm" class="form-group col-lg-5 col-md-6 col-sm-12">

ACTion

Files that are uploaded into ACTion will be given a type: Attachment, Proof of Income, or Title. This is done by using the description input and mapping it to a type on the backend API defined in appsettings.json. If a description is mistyped or not found in appsettings.json, it will default to Attachment.

The description within action is created with the inputs: section, sectionId, and description.

If section is null or blank, it is not used as shown in the code and screenshot below.

// Code segment from LoanWizardAPI/CRIF.ACTion/Files/AddAppFilesSection.cs
$"{file.Section} - {file.SectionId}: {file.Description}"
$"{file.SectionId}: {file.Description}"

Image alt text

Example Implementation

HTML

<div *ngIf="showUploadForm" class="form-group col-lg-5 col-md-6 col-sm-12">
  <lw-file-upload
    [loanId]="loanId"
    section=""
    sectionId="Personal Information"
    description="Proof of being a student"
    label="proof that you are a student"
    [removeAllFilesSubject]="removeAllFilesSubject"
    (sendFiles)="handleFiles($event)"
    (uploadingFiles)="handleUploadingFiles($event)"
    (removedAllFiles)="handleRemovedAllFiles($event)">
  </lw-file-upload>
</div>

TypeScript

  @Input()
  public group: FormGroup;

  public loanId: string;

  public showUploadForm: boolean;

  public removeAllFilesSubject: Subject<boolean>;

  constructor(private collateralInfoService: CollateralInfoFormService) {
    this.loanId = collateralInfoService.getLoanId(); // not real, just an example
    this.showUploadForm = true;
    this.removeAllFilesSubject = new Subject<boolean>();
  }

  // Somewhat of a contrived example, but essentially when the form is supposed to be deleted, the .next() should be called.
  // Once files are removed, the removedAllFiles output of the component will emit and call the function to complete removing the form handleRemovedAllFiles (below)
  public closeForm() {
    this.removeAllFilesSubject.next();
  }

  // Sets the files value of the group, called when component is initialized and when all files have been removed.
  public handleFiles(files: any[]): void {
    this.group.patchValue({ 'files': files });
  }

  // Sets a boolean to true/false for form validation so that Next is disabled
  public handleUploadingFiles(isUploading: boolean): void {
    this.group.patchValue({ 'isUploading': isUploading });
  }

  public handleRemovedAllFiles(removedAllFiles: boolean): void {
    if(removedAllFiles) {
      // Code to clear/delete form here...
    }
  }

Interface

This is the interface that the files variable should be added to. If it is in the Personal Info section, it would be added to src\app\loan-wizard\field-groups\personal\personal-information.ts

{
    ...
    // not all variables shown
    files?: any[];
    isUploading?: boolean;
    ...
}

src\app\loan-wizard\field-groups\common-groups.ts

This file is where the form group for the page is generated. It will also need to have both variables added to the correct section so they can be used with the validators.

{
    ...
    // not all variables shown
    {
      field: 'files',
      validation: [WizardValidators.FileValidator]
    },
    {
      field: 'isUploading',
      validation: [WizardValidators.MustBeFalse]
    }
    ...
}

src\assets\i18n\en.json

{
  ...
  // not all variables shown
  "BEFOREYOUBEGIN": {
    "EXAMPLE": {
      "INTRO": "Before you begin the process, you should have the following documents:",
      "HEADINGS": [
        {
          "HEADING": "Documents to Upload",
          "VALUES": [
            "Proof of income (i.e. most recent payroll check stub, 1040s for self-employed borrowers, bank statement).",
            "Proof that you are a student (i.e. Student ID from current school year or current enrollment documentation such as a class schedule)."
          ]
        }
      ]
    },
    ...
  }
}

src\app\shared\loan-type.ts

Add needed keys for checklist component, coming from en.json (see above)

  {
    ...
    // not all variables shown
    beforeYouBeginKey: 'BEFOREYOUBEGIN.EXAMPLE', // Should be added/updated whenever the upload form is added
    showProofOfIncomeUploadForm: true // Set to true if the proof of income file uploads should show, be sure to update en.json!
    ...
  }

Summary component

Add divs to display files. The description can be pulled from the first file, as shown (it is done with income files as there are multiple sections and borrowers), or the description can be hard coded. The files array is passed into the uploadedFiles pipe which parses them into a comma-separated list. The pipe is located at src\app\shared\pipes\uploaded-files.pipe.ts

<div class="row summary-card" *ngIf="personalInformation">
  <!-- full code of component not shown -->
  <div *ngIf="personalInformation?.files?.length > 0" class="col-md-4 col-sm-12 summary-card-field-title">{{personalInformation.files[0].description}} document(s)</div>
  <div *ngIf="personalInformation?.files?.length > 0" class="col-md-8 col-sm-12">{{personalInformation.files | uploadedFiles}}</div>
</div>