resources/assets/js/composables/useErrorHandler.ts

Summary

Maintainability
A
3 hrs
Test Coverage
import type { AxiosResponse } from 'axios'
import axios from 'axios'
import { logger } from '@/utils/logger'
import { parseValidationError } from '@/utils/formatters'
import { useDialogBox } from '@/composables/useDialogBox'
import { useMessageToaster } from '@/composables/useMessageToaster'

export interface StatusMessageMap {
  [key: AxiosResponse['status']]: string | Closure
}

type ErrorMessageDriver = 'toast' | 'dialog'

export const useErrorHandler = (driver: ErrorMessageDriver = 'toast') => {
  const { toastError } = useMessageToaster()
  const { showErrorDialog } = useDialogBox()

  const showError = (message: string) => driver === 'toast' ? toastError(message) : showErrorDialog(message)

  const showGenericError = () => showError('An unknown error occurred.')

  const handleHttpError = (error: unknown, statusMessageMap: StatusMessageMap = {}) => {
    logger.error(error)

    if (!axios.isAxiosError(error) || !error.response?.status) {
      return showGenericError()
    }

    if (
      !Object.prototype.hasOwnProperty.call(statusMessageMap, error.response.status)
      && error.response.status === 422
    ) {
      return showError(parseValidationError(error.response.data)[0])
    }

    const messageOrClosure = statusMessageMap[error.response.status]

    if (messageOrClosure) {
      return typeof messageOrClosure === 'string' ? showError(messageOrClosure) : messageOrClosure()
    }

    if (error.response.data.message) {
      return showError(error.response.data.message)
    }

    return showGenericError()
  }

  return {
    handleHttpError,
    showGenericError,
  }
}