import { Text } from '@mantine/core'; import { notifications } from '@mantine/notifications'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { FaCheck } from 'react-icons/fa'; import { VscLoading } from 'react-icons/vsc'; const url = `${import.meta.env.PROD ? import.meta.env.VITE_DOMAIN_PROD : import.meta.env.VITE_DOMAIN_DEV}/${import.meta.env.VITE_BASE_URL}`; const headers: HeadersInit = { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS', 'Access-Control-Allow-Credentials': 'true', 'Sec-Fetch-Mode': 'no-cors', 'Sec-Fetch-Site': 'same-site', }; const callEndpoint = async (url: string) => { const response = await fetch(url); if (!response.ok) { throw new Error(`${response.status} ${response.statusText}`); } return await response.json(); }; export function useQueryAPI({ endpoint }: { endpoint: string }) { const callEndpoint = async (endpoint: string) => { const options: object = { method: 'GET', headers: headers, }; const response = await fetch(`${url}/${endpoint}`, options); if (!response.ok) { throw new Error(`${response.status} ${response.statusText}`); } return await response.json(); }; return useQuery({ queryKey: ['GET', endpoint], queryFn: () => callEndpoint(endpoint), }); } export function useMutationAPI() { const callEndpoint = async ( method: string, endpoint: string, body: object | undefined | null, ) => { const id = notifications.show({ loading: true, title: ( {method} {endpoint} ), message: ( {body ? JSON.stringify(body) : 'Calling API...'} ), autoClose: false, withCloseButton: true, icon: , }); const options: { method: string; headers: HeadersInit | undefined; body: string } = { method: method, headers: headers, body: JSON.stringify(body), }; const response = await fetch(`${url}/${endpoint}`, options); if (!response.ok) { const responseData = await response.json(); if (typeof responseData === 'object') { if (responseData.error.code === 'ER_DUP_ENTRY') { notifications.update({ id: id, loading: false, title: ( {method} Failure! ), message: ( Entry with that name already exists. ), autoClose: 2500, icon: , }); } } return await responseData; } notifications.update({ id: id, loading: false, title: ( {method} Success! ), message: ( Called endpoint {endpoint} ), autoClose: 2500, icon: , }); return await response.json(); }; const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ method, endpoint, body = undefined, }: { method: string; endpoint: string; body: object | undefined | null; }) => callEndpoint(method, endpoint, body), onSuccess: (_, { endpoint }) => { queryClient.refetchQueries({ queryKey: ['GET', endpoint], }); endpoint === 'api/bookmarkOrder' && queryClient.refetchQueries({ queryKey: ['GET', 'api/bookmarks'] }); endpoint === 'api/bookmarkCategoryOrder' && queryClient.refetchQueries({ queryKey: ['GET', 'api/bookmarkCategories'] }); endpoint === 'api/applicationOrder' && queryClient.refetchQueries({ queryKey: ['GET', 'api/applications'] }); endpoint === 'api/applications' && queryClient.refetchQueries({ queryKey: ['GET', 'api/enabledApplications'] }); endpoint === 'api/bookmarks' && queryClient.refetchQueries({ queryKey: ['GET', 'api/themes'] }); endpoint === 'api/providers' && queryClient.refetchQueries({ queryKey: ['GET', 'api/providers/default'] }); endpoint === 'api/personalData' && queryClient.refetchQueries({ queryKey: ['GET', 'api/personalData'] }); }, }); } export function useWeatherAPI({ endpoint, lat, lon, office, station, x, y, }: { endpoint: string; lat?: number; lon?: number; office?: string; station?: string; x?: number; y?: number; }) { let url = ''; if (endpoint === 'baseline') { url = `https://api.weather.gov/gridpoints/${office}/${x},${y}`; } else if (endpoint === 'current') { url = `https://api.weather.gov/stations/${station}/observations`; } else if (endpoint === 'forecast') { url = `https://api.weather.gov/gridpoints/${office}/${x},${y}/forecast`; } else if (endpoint === 'hourly') { url = `https://api.weather.gov/gridpoints/${office}/${x},${y}/forecast/hourly`; } else if (endpoint === 'points') { url = `https://api.weather.gov/points/${lat},${lon}`; } else if (endpoint === 'stations') { url = `https://api.weather.gov/gridpoints/${office}/${x},${y}/stations`; } return useQuery({ queryKey: ['GET', url], queryFn: () => callEndpoint(url), }); } export function useSunStateAPI({ lat, lon }: { lat: number; lon: number }) { const date = new Date(); const today = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`; date.setDate(date.getDate() + 1); const tomorrow = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`; const url = `https://api.sunrisesunset.io/json?lat=${lat}&lng=${lon}&date_start=${today}&date_end=${tomorrow}`; return useQuery({ queryKey: ['GET', url], queryFn: () => callEndpoint(url), }); } export function useOSMAPI({ address }: { address: string }) { const url = `https://nominatim.openstreetmap.org/search?addressdetails=1&format=jsonv2&limit=1&q=${address?.replaceAll(' ', '+')}`; const callEndpoint = async () => { const response = await fetch(url); if (!response.ok) { throw new Error(`${response.status} ${response.statusText}`); } const data = await response.json(); return await data; }; return useQuery({ queryKey: ['GET', url], queryFn: () => callEndpoint(), }); } export function useFileUploadAPI() { const callEndpoint = async ( method: string, endpoint: string, body?: object | FormData | undefined | null, ) => { const id = notifications.show({ loading: true, title: ( {method} {endpoint} ), message: {'Uploading image...'}, autoClose: false, withCloseButton: false, icon: , }); const options = { method: method, body: body ?? undefined, }; const response = await fetch(`${url}/${endpoint}`, options as unknown as Body); if (!response.ok) { const responseData = await response.json(); if (typeof responseData === 'object') { if (responseData.error.code === 'ER_DUP_ENTRY') { notifications.update({ id: id, loading: false, title: ( {method} Failure! ), message: ( Entry with that name already exists. ), autoClose: 2500, icon: , }); } } return await responseData; } notifications.update({ id: id, loading: false, title: ( {method} Success! ), message: {response.statusText}, autoClose: 2500, icon: , }); return await response.json(); }; const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ method, endpoint, body, }: { method: string; endpoint: string; body: object | FormData | undefined | null; }) => callEndpoint(method, endpoint, body), onMutate: () => {}, onSuccess: (_variables) => { queryClient.invalidateQueries({ queryKey: ['GET', 'api/backgrounds'] }); queryClient.invalidateQueries({ queryKey: ['GET', 'api/themes'] }); queryClient.invalidateQueries({ queryKey: ['GET', 'api/themePlaylists'] }); }, }); }