UNPKG

omnipay-savings-sdk

Version:

Omnipay Savings SDK

325 lines (277 loc) 9.13 kB
import dayjs from 'dayjs'; import {API_BASE_URL} from '../env.json'; import {looseObject} from './types'; import { formDataRequests, isValidDate, parseQueryString, waitFor, } from '../utils'; import {useToast} from '../contexts/ToastProvider'; // Global token expiry handler let globalTokenExpiryHandler: (() => void) | null = null; export const setTokenExpiryHandler = (handler: (() => void) | null) => { globalTokenExpiryHandler = handler; }; const handleTokenExpiry = () => { if (globalTokenExpiryHandler) { globalTokenExpiryHandler(); } }; let isRefreshingRequestToken = false; type RequestContent = 'form-data' | 'json'; type RequestObject = { requestUrl: string; customHeaders?: looseObject; }; interface RequestPostObject extends RequestObject { requestData: looseObject; requestType?: RequestContent; } export const POST = async (params: RequestPostObject & {apiKey: string}) => { const {requestUrl, requestData, customHeaders, requestType, apiKey} = params; try { let data = formatRequestData(requestData, requestType); const requestHeaders = await getRequestHeaders(apiKey, requestType); const headers = { ...requestHeaders.headers, ...customHeaders, }; const response = await fetch(`${API_BASE_URL}${requestUrl}`, { method: 'POST', headers, body: JSON.stringify(data), }); const responseData = await response.json(); if (!response.ok || responseData.error === true) { // Handle 401 unauthorized responses if (response.status === 401) { handleTokenExpiry(); } return { error: extractDetailedErrorMessage(responseData), status: responseData?.status, }; } return responseData; } catch (error: any) { const errorMessage = getErrorMessage(error); const errorResponse = error?.response || {}; const errorData = errorResponse.data || {}; return Promise.reject(errorData); } }; export const PUT = async (params: RequestPostObject & {apiKey: string}) => { const {requestUrl, requestData, customHeaders, requestType, apiKey} = params; try { let data = formatRequestData(requestData, requestType); const requestHeaders = await getRequestHeaders(apiKey, requestType); const headers = { ...requestHeaders.headers, ...customHeaders, }; const response = await fetch(`${API_BASE_URL}${requestUrl}`, { method: 'PUT', headers, body: JSON.stringify(data), }); const responseData = await response.json(); if (!response.ok || responseData.error === true) { // Handle 401 unauthorized responses if (response.status === 401) { handleTokenExpiry(); } return { error: extractDetailedErrorMessage(responseData), status: responseData?.status, }; } return responseData; } catch (error: any) { const errorMessage = getErrorMessage(error); const errorResponse = error?.response || {}; const errorData = errorResponse.data || {}; return Promise.reject(errorData); } }; export const GET = async (params: RequestObject & {apiKey: string}) => { const {requestUrl, customHeaders, apiKey} = params; try { const requestHeaders = await getRequestHeaders(apiKey); const headers = { ...requestHeaders.headers, ...customHeaders, }; let modifiedDateUrl = modifyUrl(requestUrl); const response = await fetch(`${API_BASE_URL}${modifiedDateUrl}`, { method: 'GET', headers, }); // console.log(response, `response`); if (!response.ok) { // Handle 401 unauthorized responses if (response.status === 401) { handleTokenExpiry(); } throw new Error(`HTTP error! status: ${response.status}`); } const responseData = await response.text(); console.log(responseData, 'response-data'); if (responseData.endsWith('.csv')) { return responseData; } return JSON.parse(responseData).responseData || JSON.parse(responseData); } catch (error: any) { // Handle fetch errors that might also be 401 if (error?.message?.includes('401') || error?.response?.status === 401) { handleTokenExpiry(); } const errorMessage = getErrorMessage(error); throw new Error(errorMessage); } }; function extractDetailedErrorMessage(responseData: any): string { // Extract detailed validation errors if available if (responseData.errors) { // Handle validation errors object if (typeof responseData.errors === 'object') { const errorMessages = []; // Check for array of errors if (Array.isArray(responseData.errors)) { errorMessages.push(...responseData.errors); } else { // Check for object with error properties for (const [key, value] of Object.entries(responseData.errors)) { if (Array.isArray(value)) { errorMessages.push(...value); } else if (typeof value === 'string') { errorMessages.push(value); } } } if (errorMessages.length > 0) { return errorMessages.join('. '); } } } // Fallback to message or title return responseData.message ?? responseData.title ?? 'An error occurred. Please try again'; } function getErrorMessage(error: any) { const errorCode = error?.response?.status; const errorData = error?.response?.data; const errorMessage = errorData?.message; if (error.message === 'Network Error') { return 'Check your network connection'; } if (errorCode === 500) { return 'Ooops. Please try again'; } if (error?.response?.message) { if (typeof error.response.message === 'string') { return error.response.message; } } return typeof errorData === 'string' && errorData ? errorData : errorMessage || error.message; } export async function getRequestHeaders( apiKey: string, requestType?: RequestContent, ) { const token = apiKey; return { headers: { ...(!!token && {authorization: `Bearer ${token}`}), 'content-type': requestType === 'form-data' ? 'multipart/form-data' : 'application/json', }, }; } function modifyUrl(requestUrl: string) { if (requestUrl.includes('?') && requestUrl.split('?')[1].includes('Date')) { const currentParamsObject = parseQueryString(requestUrl.split('?')[1]); let newRequestParamsObject = {}; for (const key in currentParamsObject) { if ( key.includes('StartDate') || key.includes('EndDate') || (key === 'date' && currentParamsObject.StartDate === undefined) ) { const isSingleDateKey = key === 'date'; if (key.includes('StartDate') || isSingleDateKey) { const keySuffix = isSingleDateKey ? '' : key.split('StartDate')[0]; let endDateKey = `${keySuffix}EndDate`; if (endDateKey === 'createenddate') { endDateKey = 'createdenddate'; } let startDateValue = currentParamsObject[key]; let endDateValue = currentParamsObject[endDateKey]; if (isValidDate(startDateValue)) { startDateValue = dayjs //@ts-ignore .utc(dayjs(startDateValue, 'YYYY-MM-DD').startOf('day')) .format(); } if (isValidDate(endDateValue)) { endDateValue = dayjs //@ts-ignore .utc(dayjs(endDateValue, 'YYYY-MM-DD').endOf('day')) .format(); } //@ts-ignore newRequestParamsObject[key] = startDateValue; //@ts-ignore newRequestParamsObject[endDateKey] = endDateValue; } } else { if (Array.isArray(currentParamsObject[key])) { //@ts-ignore newRequestParamsObject[key] = currentParamsObject[key][0]; } else { //@ts-ignore newRequestParamsObject[key] = currentParamsObject[key]; } } } const newParamsUrl = Object.keys(newRequestParamsObject) //@ts-ignore .map(key => key + '=' + newRequestParamsObject[key]) .join('&'); let modifiedDateUrl = `${requestUrl.split('?')[0]}?${newParamsUrl}`; return modifiedDateUrl; } return requestUrl; } export function formatRequestData( requestData: looseObject, requestType?: RequestContent, ) { if (requestType === 'form-data') { let fd = new FormData(); for (const el in requestData) { let data = requestData[el]; if (formDataRequests.includes(el)) { const uriParts = data?.split('.'); const fileType = uriParts?.[uriParts.length - 1]; if (data && uriParts && fileType) { // @ts-ignore fd.append(el, { uri: data, name: `${el}.${fileType}`, type: fileType.toLowerCase().includes('pdf') ? `application/${fileType.toLowerCase()}` : `image/${fileType.toLowerCase()}`, } as any); } } else { fd.append(el, data); } } return fd; } return requestData; }