Repository: h2oai/wave
File: ui/src/file_upload.tsx (TypeScript)

Code before:
      border: dashed(2, colors.text),
    },
    uploadLabel: {
      ...centerMixin(),
      padding: 15,
      background: colors.text,
      color: colors.page,
      minWidth: 80,
      $nest: {
        '&:hover': {
          cursor: 'pointer'
        }
      }
    },
    uploadMessageBar: {
      margin: '20px 0'
    },
    uploadRemove: {
      fontSize: 20,
      position: 'absolute',
      top: -15,
      right: 0,
      cursor: 'pointer'
    }
  })
const convertBytesToMegabytes = (bytes: number) => bytes * 1024 * 1024
export const
  XFileUpload = bond(({ model }: { model: FileUpload }) => {
    const
      isDraggingB = box(false),
      filesB = box<File[]>([]),
      percentCompleteB = box(0.0),
      errorB = box(''),
      successMsgB = box(''),
      maxSizePerFileMb = model.maxSizePerFile ? convertBytesToMegabytes(model.maxSizePerFile) : 0,
      maxSizeTotalMb = model.maxSizeTotal ? convertBytesToMegabytes(model.maxSizeTotal) : 0,
      upload = async () => {
        const formData = new FormData()

        filesB().forEach(f => formData.append('files', f))

        try {
          const makeRequest = new Promise<XMLHttpRequest>((resolve, reject) => {
            const xhr = new XMLHttpRequest()
            xhr.open("POST", "/_f")
            xhr.upload.onprogress = e => percentCompleteB(e.loaded / e.total)
            xhr.send(formData)
            xhr.onreadystatechange = () => {
              if (xhr.readyState !== XMLHttpRequest.DONE) return
              if (xhr.status >= 200 && xhr.status < 300) resolve(xhr)
              else reject(xhr)

Review comment (suggestion):
```suggestion
const convertBytesToMegabytes = (bytes: F) => bytes * 1024 * 1024
```

Code after:
      border: dashed(2, colors.text),
    },
    uploadLabel: {
      ...centerMixin(),
      padding: 15,
      background: colors.text,
      color: colors.page,
      minWidth: 80,
      $nest: {
        '&:hover': {
          cursor: 'pointer'
        }
      }
    },
    uploadMessageBar: {
      margin: '20px 0'
    },
    uploadRemove: {
      fontSize: 20,
      position: 'absolute',
      top: -15,
      right: 0,
      cursor: 'pointer'
    }
  })
const convertMegabytesToBytes = (bytes: F) => bytes * 1024 * 1024
export const
  XFileUpload = bond(({ model }: { model: FileUpload }) => {
    const
      isDraggingB = box(false),
      filesB = box<File[]>([]),
      percentCompleteB = box(0.0),
      errorB = box(''),
      successMsgB = box(''),
      maxFileSizeBytes = model.max_file_size ? convertMegabytesToBytes(model.max_file_size) : 0,
      maxSizeBytes = model.max_size ? convertMegabytesToBytes(model.max_size) : 0,
      fileExtensions = model.file_extensions
        ? model.file_extensions.map(e => e.startsWith('.') ? e : `.${e}`)
        : null,
      upload = async () => {
        const formData = new FormData()

        filesB().forEach(f => formData.append('files', f))

        try {
          const makeRequest = new Promise<XMLHttpRequest>((resolve, reject) => {
            const xhr = new XMLHttpRequest()
            xhr.open("POST", "/_f")
            xhr.upload.onprogress = e => percentCompleteB(e.loaded / e.total)
            xhr.send(formData)
            xhr.onreadystatechange = () => {