157 lines
4.0 KiB
TypeScript
157 lines
4.0 KiB
TypeScript
import { DashboardQuery } from './query'
|
|
import { formatISO } from './util/date'
|
|
import { serializeApiFilters } from './util/filters'
|
|
|
|
let abortController = new AbortController()
|
|
let SHARED_LINK_AUTH: null | string = null
|
|
|
|
export class ApiError extends Error {
|
|
payload: unknown
|
|
constructor(message: string, payload: unknown) {
|
|
super(message)
|
|
this.name = 'ApiError'
|
|
this.payload = payload
|
|
}
|
|
}
|
|
|
|
function serializeUrlParams(params: Record<string, string | boolean | number>) {
|
|
const str: string[] = []
|
|
/* eslint-disable-next-line no-prototype-builtins */
|
|
for (const p in params)
|
|
if (params.hasOwnProperty(p)) {
|
|
str.push(`${encodeURIComponent(p)}=${encodeURIComponent(params[p])}`)
|
|
}
|
|
return str.join('&')
|
|
}
|
|
|
|
export function setSharedLinkAuth(auth: string) {
|
|
SHARED_LINK_AUTH = auth
|
|
}
|
|
|
|
export function cancelAll() {
|
|
abortController.abort()
|
|
abortController = new AbortController()
|
|
}
|
|
|
|
export function queryToSearchParams(
|
|
query: DashboardQuery,
|
|
extraQuery: unknown[] = []
|
|
): string {
|
|
const queryObj: Record<string, string> = {}
|
|
if (query.period) {
|
|
queryObj.period = query.period
|
|
}
|
|
if (query.date) {
|
|
queryObj.date = formatISO(query.date)
|
|
}
|
|
if (query.from) {
|
|
queryObj.from = formatISO(query.from)
|
|
}
|
|
if (query.to) {
|
|
queryObj.to = formatISO(query.to)
|
|
}
|
|
if (query.filters) {
|
|
queryObj.filters = serializeApiFilters(query.filters)
|
|
}
|
|
if (query.with_imported) {
|
|
queryObj.with_imported = String(query.with_imported)
|
|
}
|
|
|
|
if (query.comparison) {
|
|
queryObj.comparison = query.comparison
|
|
queryObj.compare_from = query.compare_from
|
|
? formatISO(query.compare_from)
|
|
: undefined
|
|
queryObj.compare_to = query.compare_to
|
|
? formatISO(query.compare_to)
|
|
: undefined
|
|
queryObj.match_day_of_week = String(query.match_day_of_week)
|
|
}
|
|
|
|
const sharedLinkParams = getSharedLinkSearchParams()
|
|
if (sharedLinkParams.auth) {
|
|
queryObj.auth = sharedLinkParams.auth
|
|
}
|
|
|
|
if (
|
|
query.legacy_time_on_page_cutoff &&
|
|
validDate(query.legacy_time_on_page_cutoff)
|
|
) {
|
|
queryObj.include = JSON.stringify({
|
|
legacy_time_on_page_cutoff: query.legacy_time_on_page_cutoff
|
|
})
|
|
}
|
|
|
|
Object.assign(queryObj, ...extraQuery)
|
|
|
|
return serializeUrlParams(queryObj)
|
|
}
|
|
|
|
function validDate(dateString: string) {
|
|
const date = new Date(dateString)
|
|
return isFinite(date.getTime())
|
|
}
|
|
|
|
function getHeaders(): Record<string, string> {
|
|
return SHARED_LINK_AUTH ? { 'X-Shared-Link-Auth': SHARED_LINK_AUTH } : {}
|
|
}
|
|
|
|
async function handleApiResponse(response: Response) {
|
|
const payload = await response.json()
|
|
if (!response.ok) {
|
|
throw new ApiError(payload.error, payload)
|
|
}
|
|
|
|
return payload
|
|
}
|
|
|
|
function getSharedLinkSearchParams(): Record<string, string> {
|
|
return SHARED_LINK_AUTH ? { auth: SHARED_LINK_AUTH } : {}
|
|
}
|
|
|
|
export async function get(
|
|
url: string,
|
|
query?: DashboardQuery,
|
|
...extraQueryParams: unknown[]
|
|
) {
|
|
const queryString = query
|
|
? queryToSearchParams(query, [...extraQueryParams])
|
|
: serializeUrlParams(getSharedLinkSearchParams())
|
|
|
|
const response = await fetch(queryString ? `${url}?${queryString}` : url, {
|
|
signal: abortController.signal,
|
|
headers: { ...getHeaders(), Accept: 'application/json' }
|
|
})
|
|
|
|
return handleApiResponse(response)
|
|
}
|
|
|
|
export const mutation = async <
|
|
TBody extends Record<string, unknown> = Record<string, unknown>
|
|
>(
|
|
url: string,
|
|
options:
|
|
| { body: TBody; method: 'PATCH' | 'PUT' | 'POST' }
|
|
| { method: 'DELETE' }
|
|
) => {
|
|
const queryString = serializeUrlParams(getSharedLinkSearchParams())
|
|
const fetchOptions =
|
|
options.method === 'DELETE'
|
|
? {}
|
|
: {
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(options.body)
|
|
}
|
|
const response = await fetch(queryString ? `${url}?${queryString}` : url, {
|
|
method: options.method,
|
|
headers: {
|
|
...getHeaders(),
|
|
...fetchOptions.headers,
|
|
Accept: 'application/json'
|
|
},
|
|
body: fetchOptions.body,
|
|
signal: abortController.signal
|
|
})
|
|
return handleApiResponse(response)
|
|
}
|