295 lines
8.2 KiB
TypeScript
295 lines
8.2 KiB
TypeScript
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: (
|
|
<Text fw={600} c={'var(--mantine-color-accent-0)'}>
|
|
{method} {endpoint}
|
|
</Text>
|
|
),
|
|
message: (
|
|
<Text c={'var(--mantine-color-primary-0)'}>
|
|
{body ? JSON.stringify(body) : 'Calling API...'}
|
|
</Text>
|
|
),
|
|
autoClose: false,
|
|
withCloseButton: true,
|
|
icon: <VscLoading size={24} />,
|
|
});
|
|
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: (
|
|
<Text fw={600} c={'var(--mantine-color-accent-0)'}>
|
|
{method} Failure!
|
|
</Text>
|
|
),
|
|
message: (
|
|
<Text c={'var(--mantine-color-primary-0)'}>
|
|
Entry with that name already exists.
|
|
</Text>
|
|
),
|
|
autoClose: 2500,
|
|
icon: <FaCheck size={24} />,
|
|
});
|
|
}
|
|
}
|
|
return await responseData;
|
|
}
|
|
notifications.update({
|
|
id: id,
|
|
loading: false,
|
|
title: (
|
|
<Text fw={600} c={'var(--mantine-color-accent-0)'}>
|
|
{method} Success!
|
|
</Text>
|
|
),
|
|
message: (
|
|
<Text c={'var(--mantine-color-primary-0)'}>Called endpoint {endpoint}</Text>
|
|
),
|
|
autoClose: 2500,
|
|
icon: <FaCheck size={24} />,
|
|
});
|
|
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: (
|
|
<Text fw={600} c={'var(--mantine-color-accent-0)'}>
|
|
{method} {endpoint}
|
|
</Text>
|
|
),
|
|
message: <Text c={'var(--mantine-color-primary-0)'}>{'Uploading image...'}</Text>,
|
|
autoClose: false,
|
|
withCloseButton: false,
|
|
icon: <VscLoading size={24} />,
|
|
});
|
|
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: (
|
|
<Text fw={600} c={'var(--mantine-color-accent-0)'}>
|
|
{method} Failure!
|
|
</Text>
|
|
),
|
|
message: (
|
|
<Text c={'var(--mantine-color-primary-0)'}>
|
|
Entry with that name already exists.
|
|
</Text>
|
|
),
|
|
autoClose: 2500,
|
|
icon: <FaCheck size={24} />,
|
|
});
|
|
}
|
|
}
|
|
return await responseData;
|
|
}
|
|
notifications.update({
|
|
id: id,
|
|
loading: false,
|
|
title: (
|
|
<Text fw={600} c={'var(--mantine-color-accent-0)'}>
|
|
{method} Success!
|
|
</Text>
|
|
),
|
|
message: <Text c={'var(--mantine-color-primary-0)'}>{response.statusText}</Text>,
|
|
autoClose: 2500,
|
|
icon: <FaCheck size={24} />,
|
|
});
|
|
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'] });
|
|
},
|
|
});
|
|
}
|