useApi.ts 3.74 KB
import type { Ref } from 'vue'
import { useKeycloakStore } from '@/@core/stores/keycloakStore'
import { useAuthFetch } from '@/composables/useAuthFetch'
import keycloakInstance from '@/keycloak'

const BASE_URL = 'https://api.ui.ac.id'
const keycloakStore = useKeycloakStore()

// --- Interface Definitions ---

interface PasswordPayload {
  oldPassword: string
  newPassword: string
}

interface ApiErrorDetail {
  message: string
  details?: any
}

interface ApiErrorResponse {
  success: false
  code: number
  error: ApiErrorDetail
  message?: string
}

export function useCivitasApi() {
  const loading = ref(false)
  const error: Ref<string | null> = ref(null)
  const errorResponse: Ref<ApiErrorResponse | null> = ref(null)

  const fetchWithAuth = async <T = any>(
    endpoint: string,
    options: Record<string, any> = {},
  ) => {
    loading.value = true
    error.value = null
    errorResponse.value = null

    const url = `${BASE_URL}${
      endpoint.startsWith('/') ? endpoint : `/${endpoint}`
    }`

    const responseData: Ref<T | null> = ref(null)
    const errorRef: Ref<any | null> = ref(null)

    const currentTime = Math.floor(Date.now() / 1000) // Current time in seconds
    const tokenExp = keycloakInstance.tokenParsed?.exp ?? 0 // Token expiration time in seconds

    const timeRemaining = tokenExp - currentTime // Time remaining in seconds

    if (timeRemaining < 5) {
      console.log('Token hampir expired, mencoba refresh...')
      await keycloakStore.updateToken() // Refresh the token if it's about to expire
    }

    try {
      const { data, error: fetchError } = await useAuthFetch<
        T | ApiErrorResponse
      >(url, options)

      responseData.value = data as Ref<T | null>
      errorRef.value = fetchError

      // so up until this is work

      if (fetchError.value) {
        const errorData = fetchError.value.data as ApiErrorResponse

        errorResponse.value = errorData

        if (errorData?.error?.message) {
          error.value = errorData.error.message
        }
        else if (errorData?.message) {
          error.value = errorData.message
        }
        else {
          error.value
            = fetchError.value.message || 'An error occurred during fetch'
        }
        console.error('API call error details:', fetchError.value)
      }
    }
    catch (err: any) {
      error.value
        = err.message || 'An unexpected network or setup error occurred'
      console.error('API call exception:', err)
      errorResponse.value = {
        success: false,
        code: 0,
        error: { message: error.value || 'Unknown error' },
      }
      errorRef.value = { message: error.value }
    }
    finally {
      loading.value = false
    }

    return {
      response: responseData,
      error: errorRef,
      fetchError: error,
      errorResponse,
    }
  }

  // Grouped API endpoints
  const api = {
    staf: {
      getStafData: (stafNIP: number) =>
        fetchWithAuth(`/staf/${stafNIP}`),
    },
    dosen: {
      getListDosen: () =>
        fetchWithAuth('/listdosen'),
    },
    user: {
      getRiwayatAkademik: () => fetchWithAuth('/my/ac'),

      getProfile: () => fetchWithAuth('/me'),

      getParkirAktif: () => fetchWithAuth('/my/parkir/aktif'),

      getAttendance: () => fetchWithAuth('/my/hr/attendance'),

      getLib: () => fetchWithAuth('/my/lib'),

      changePassword: (payload: PasswordPayload) =>
        fetchWithAuth('/my/pw', {
          method: 'POST',
          body: JSON.stringify(payload),
          headers: {
            'Content-Type': 'application/json',
          },
        }),

      // getPublicPhoto: (kodeIdentitas: number) =>
      //   fetchWithAuth(`/public/photo/${kodeIdentitas}.jpg`),
    },
  }

  return {
    api,
    loading,
    error,
    errorResponse,
  }
}