Source: services/api.js

/**
 * @module services/api
 */
import { appContent } from "../constants/dom.js";
import { filterSetAction } from "../components/filter.js";
import { loaderAdd, loaderRemove } from "../components/loader.js";
import { messageRemove, messageError404Add } from "../components/message.js";

/**
 * @function apiAddLink
 * @description Add link of the API to the app content
 * @param {string} url - root of the API
 * @see {@link module:scripts|scripts.js}
 */
export function apiAddLink(url) {
	const linkId = document.getElementById("linkApi");

	if (!linkId) {
		const link = document.createElement("a");
		const linkText = document.createTextNode(url);

		link.setAttribute("id", "linkApi");
		link.setAttribute("href", url);
		link.setAttribute("target", "_blank");
		link.appendChild(linkText);
		appContent.appendChild(link);
	}
}

/**
 * @function apiAjaxHandler
 * @description API request
 * @param {string} url - root of the API
 * @param {string} action - name of the action to execute
 * @see {@link module:components/loader~loaderAdd|loaderAdd}
 * @see {@link module:components/loader~loaderRemove|loaderRemove}
 * @see {@link module:components/filter~filterSetAction|filterSetAction}
 * @see {@link module:components/search~searchAdd|searchAdd}
 * @see {@link module:components/pagination~paginationAdd|paginationAdd}
 * @see {@link module:scripts|scripts.js}
 */
export function apiAjaxHandler(url, action) {
	loaderAdd();

	fetch(url).
		then(handleResponse).
		then(function(data) {
			// console.log("%c--- Promise 2 ---", "padding: 0.5rem 1rem; color: #C0C0C0; background-color: #454545;");
			// console.info(data);
			// console.info('data is', data);
			const timer = setInterval(function() {
				clearInterval(timer);
				loaderRemove();
				messageRemove("messageError404");
				filterSetAction(action, appContent, data);
			}, 3000);
		}).
		catch(function(error) {
			// console.warn('error is', error);
			if (error.status === 404) {
				loaderRemove();
				messageError404Add();
			}
		});

	/**
	 * @function handleResponse
	 * @description Route the response to the correct handler based on content type
	 * @param {Response} response - fetch response object
	 * @returns {Promise} returns the parsed response
	 */
	function handleResponse(response) {
		const contentType = response.headers.get("content-type");
		if (contentType?.includes("application/json")) {
			return handleJSONResponse(response);
		} else if (contentType?.includes("text/html")) {
			return handleTextResponse(response);
		}

		// Other response types as necessary. I haven't found a need for them yet though.
		throw new Error(`Sorry, content-type ${contentType} not supported`);
	}

	/**
	 * @function handleJSONResponse
	 * @description Parse a JSON response and reject if not ok
	 * @param {Response} response - fetch response object
	 * @returns {Promise} returns the parsed JSON or a rejected promise
	 */
	function handleJSONResponse(response) {
		return response.json().then(json => {
			if (response.ok) {
				return json;
			}

			return Promise.reject(Object.assign(new Error(response.statusText), {
				...json,
				"status": response.status,
			}));
		});
	}

	/**
	 * @function handleTextResponse
	 * @description Parse a text response and reject if not ok
	 * @param {Response} response - fetch response object
	 * @returns {Promise} returns the parsed text or a rejected promise
	 */
	function handleTextResponse(response) {
		return response.text().then(text => {
			if (response.ok) {
				return text;
			}

			return Promise.reject(Object.assign(new Error(response.statusText), {
				"status": response.status,
				"err": text,
			}));
		});
	}
}