Experiments >

Claim AutoFill: Filing a single claim

Experiment #21518th July, 2021by Joshua Nussbaum

Continuing on with my claim autofill chrome extension, I got it to the point where it can fill out the entire form.

Code

For now it uses static data, but the real world the data would come from the database:

<!-- in App.svelte -->
<script>
  let shipments = [
    {
      tracking: '1234000000000000001',
      status: 'pending',
      insuranceFees: 2.20,
      mailingDate: new Date(2021, 2, 22),
      item: {
        name: 'Camera',
        type: '06',
        description: 'Digital camera',
        purchaseDate: new Date(2021, 2, 20)
      },
      claim: {
        reason: 'damage',
        amount: 100
      },
      files: [
        {
          name: 'receipt.png',
          data: 'data:image/png;base64,iVBORw0KGgoA.....'
        }
      ],
      origin: {
        firstName: 'John',
        initial: 'Q',
        lastName: 'Smith',
        company: 'ACME Corporation',
        address1: '1234 Main Street',
        address2: 'Suite 100',
        city: 'New York',
        state: 'NY',
        zip: '11111',
        email: 'jqsmith@acme.com',
        phone: '123-123-1234'
      },
      destination: {
        firstName: 'Jane',
        initial: 'L',
        lastName: 'Smith',
        company: 'ACME Corporation',
        address1: '1234 Main Street',
        address2: 'Suite 100',
        city: 'New York',
        state: 'NY',
        zip: '11111',
        email: 'jqsmith@acme.com',
        phone: '123-123-1234'
      }
    },
    // ... more here
  }
<script>

Then when the user clicks “submit” in the extension:

<script>
  let shipments = { /* hardcoded data here */ }

  async function submit(shipment) {
    // open fake USPS site (for testing)
    await sendMessage({
      type: 'open',
      url: 'http://usps.local'
    })

    await sleep(2000)

    // send messages to content script
    await sendMessage({
      type: 'input',
      field: 'tracking',
      value: shipment.tracking
    })

    await sendMessage({
      type: 'input',
      field: 'mailing_date',
      value: format(shipment.mailingDate, "yyyy-MM-dd")
    })

    await sendMessage({
      type: 'select',
      field: 'mail_class',
      value: 'first-class-mail'
    })

    await sendMessage({
      type: 'select',
      field: 'claim_reason',
      value: shipment.claim.reason
    })

    await sendMessage({
      type: 'input',
      field: 'insurance_fees',
      value: shipment.insuranceFees
    })

    await sendMessage({
      type: 'radio',
      field: 'mailer_or_addressee',
      value: 'mailer'
    })

    await sendMessage({
      type: 'input',
      field: 'mailer_first_name',
      value: shipment.origin.firstName
    })

    await sendMessage({
      type: 'input',
      field: 'mailer_middle_initial',
      value: shipment.origin.initial
    })

    await sendMessage({
      type: 'input',
      field: 'mailer_last_name',
      value: shipment.origin.lastName
    })

    await sendMessage({
      type: 'input',
      field: 'mailer_company',
      value: shipment.origin.company
    })

    await sendMessage({
      type: 'input',
      field: 'mailer_address1',
      value: shipment.origin.address1
    })

    await sendMessage({
      type: 'input',
      field: 'mailer_address2',
      value: shipment.origin.address2
    })

    await sendMessage({
      type: 'input',
      field: 'mailer_city',
      value: shipment.origin.city
    })

    await sendMessage({
      type: 'select',
      field: 'mailer_state',
      value: shipment.origin.state
    })

    await sendMessage({
      type: 'input',
      field: 'mailer_zip',
      value: shipment.origin.zip
    })

    await sendMessage({
      type: 'input',
      field: 'mailer_email',
      value: shipment.origin.email
    })

    await sendMessage({
      type: 'input',
      field: 'mailer_tel',
      value: shipment.origin.phone
    })

    await sendMessage({
      type: 'input',
      field: 'addressee_first_name',
      value: shipment.destination.firstName
    })

    await sendMessage({
      type: 'input',
      field: 'addressee_middle_initial',
      value: shipment.destination.initial
    })

    await sendMessage({
      type: 'input',
      field: 'addressee_last_name',
      value: shipment.destination.lastName
    })

    await sendMessage({
      type: 'input',
      field: 'addressee_company',
      value: shipment.destination.company
    })

    await sendMessage({
      type: 'input',
      field: 'addressee_address1',
      value: shipment.destination.address1
    })

    await sendMessage({
      type: 'input',
      field: 'addressee_address2',
      value: shipment.destination.address2
    })

    await sendMessage({
      type: 'input',
      field: 'addressee_city',
      value: shipment.destination.city
    })

    await sendMessage({
      type: 'select',
      field: 'addressee_state',
      value: shipment.destination.state
    })

    await sendMessage({
      type: 'input',
      field: 'addressee_zip',
      value: shipment.destination.zip
    })

    await sendMessage({
      type: 'input',
      field: 'addressee_email',
      value: shipment.destination.email
    })

    await sendMessage({
      type: 'input',
      field: 'addressee_tel',
      value: shipment.destination.phone
    })

    await sendMessage({
      type: 'input',
      field: 'payment_first_name',
      value: shipment.origin.firstName
    })

    await sendMessage({
      type: 'input',
      field: 'payment_middle_initial',
      value: shipment.origin.initial
    })

    await sendMessage({
      type: 'input',
      field: 'payment_last_name',
      value: shipment.origin.lastName
    })

    await sendMessage({
      type: 'input',
      field: 'payment_company',
      value: shipment.origin.company
    })

    await sendMessage({
      type: 'input',
      field: 'payment_address1',
      value: shipment.origin.address1
    })

    await sendMessage({
      type: 'input',
      field: 'payment_address2',
      value: shipment.origin.address2
    })

    await sendMessage({
      type: 'input',
      field: 'payment_city',
      value: shipment.origin.city
    })

    await sendMessage({
      type: 'select',
      field: 'payment_state',
      value: shipment.origin.state
    })

    await sendMessage({
      type: 'input',
      field: 'payment_zip',
      value: shipment.origin.zip
    })

    await sendMessage({
      type: 'input',
      field: 'payment_email',
      value: shipment.origin.email
    })

    await sendMessage({
      type: 'input',
      field: 'payment_tel',
      value: shipment.origin.phone
    })

    await sendMessage({
      type: 'input',
      field: 'item_name',
      value: shipment.item.name
    })

    await sendMessage({
      type: 'select',
      field: 'item_type',
      value: shipment.item.type
    })

    await sendMessage({
      type: 'textarea',
      field: 'item_description',
      value: shipment.item.description
    })

    await sendMessage({
      type: 'input',
      field: 'purchase_date',
      value: format(shipment.item.purchaseDate, "yyyy-MM-dd")
    })

    await sendMessage({
      type: 'input',
      field: 'amount_requested',
      value: shipment.claim.amount
    })

    await sendMessage({
      type: 'file',
      field: 'proof_of_value',
      files: shipment.files
    })

    await sendMessage({
      type: 'input',
      field: 'nickname',
      value: `Claim for #${shipment.tracking}`
    })
  }

  // function to send messages to content script in active tab
  async function sendMessage(message) {
    return new Promise((resolve) => {
      chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
        chrome.tabs.sendMessage(tabs[0].id, message, (response) => {
          resolve(response.farewell)
        })
      })
    })
  }

  // utlity function to promisify setTimeout()
  async function sleep(ms) {
    return new Promise(resolve => {
      setTimeout(resolve, ms)
    })
  }
</script>

<!-- display list of shipments -->
{#each shipments as shipment}
  <div>
    <h2>{shipment.tracking}</h2>
    <button on:click={() => submit(shipment)}>Submit</a>
  </div>
{/each}

In the content script, I handle the messages:

// src/contentScript.js

/*
 * this runs in the context of the page
 * and receives messages from the extension
 */

/*global chrome */
console.log('AutoFill extension loaded')

function dataURLtoBlob(dataurl) {
  let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n)

  while(n--){
    u8arr[n] = bstr.charCodeAt(n)
  }

  return new Blob([u8arr], {type:mime})
}

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  console.log('Received', message)

  switch (message.type) {
  case 'open':
    location.href = message.url
    sendResponse(true)
    break
  case 'input':
    document.querySelector(`input[name=${message.field}]`).value = message.value
    sendResponse(true)
    break
  case 'textarea':
    document.querySelector(`textarea[name=${message.field}]`).value = message.value
    sendResponse(true)
    break
  case 'radio':
    document.querySelector(`input[name=${message.field}][value=${message.value}]`).checked = true
    sendResponse(true)
    break
  case 'select':
    document.querySelector(`select[name=${message.field}]`).value = message.value
    sendResponse(true)
    break
  case 'file':
    const dt = new DataTransfer()

    message.files.forEach(file => {
      const blob = dataURLtoBlob(file.data)
      dt.items.add(new File([blob], file.name))
    })

    const input = document.querySelector(`input[type=file][name=${message.field}]`)
    input.files = dt.files
    input.dispatchEvent(new Event('change'))

    sendResponse(true)

    break
  case 'submit':
    document.querySelector('form').dispatchEvent(new Event('submit'))
    sendResponse(true)
    break
  }
})

Demo

Notes

  • Wire up database
  • Add login requirement before using extension
  • Submit multiple at once
  • Think about whether it shoul just fill, or fill and submit in one shot
view all experiments

Stay tuned in

Learn how to add more experimentation to your workflow