// This file houses crud methods to interact with landmarks on the server. They are generally called by react query mutations.
import axios, { AxiosRequestConfig } from "axios"
import { Region } from "react-native-maps";
import { QueryClient, useMutation, useQuery, useQueryClient } from "react-query";
import { API_URL, reportAxiosError as reportAxiosError } from "../globals"
import { authStore } from "../stores/AuthStore";
import { useAuth } from "./useAuth";
/**
* Interface representing a landmark's comment.
*/
export interface LMComment {
/**
* The comment's id.
*/
id: string,
/**
* The id of the user who posted the comment
*/
poster: string,
/**
* The text content of the comment
*/
text: string
/**
* The landmark that this comment is associated with.
*/
landmark: Landmark
}
/**
* Interface representing a landmark object
*/
export interface Landmark {
/**
* The id of the landmark.
*/
id?: string | null,
/**
* The rating of the landmark.
*/
rating?: number | null,
/**
* The id of the user who created the landmark.
*/
user?: string | null,
/**
* The longitude of the landmark's location.
*/
longitude?: number | null,
/**
* The latitude of the landmark's location.
*/
latitude?: number | null,
/**
* The landmark's title.
*/
title?: string | null,
/**
* The landmark's description.
*/
description?: string | null,
/**
* User [comments]{@link LMComment} associated with this landmark.
*/
comments?: LMComment[] | null,
/**
* An integer representing the type of this landmark.
*/
landmark_type?: number | null, // for working with existing database schema, should be changed
/**
* A Date object representing when this landmark was created.
*/
time?: Date | null
}
/**
* A custom hook containing [react-query]{@link https://react-query.tanstack.com/} queries and mutations and other logic related to interacting with {@link Landmark} objects.
* @category Hooks
* @namespace useLandmarks
*/
export const useLandmarks = (region: Region | undefined) => {
const { refreshAccessToken } = useAuth();
/**
* The local instance of the [react-query QueryClient]{@link https://react-query.tanstack.com/reference/QueryClient#_top}.
* @memberOf useLandmarks
*/
let queryClient: QueryClient;
try {
queryClient = useQueryClient()
} catch (error) {
console.log("Something went wrong when retrieving query client:")
console.log(error)
}
/**
* The callback responsible for retrieving {@link Landmark} from the API, used by the [react-query useQuery]{@link https://react-query.tanstack.com/reference/useQuery#_top} hook.
* * @memberOf useLandmarks
*/
const getLandmarks = async (region: Region | undefined) => {
// if (region) {
const config: AxiosRequestConfig = {
method: 'GET',
// url: `${API_URL}/api/landmarks/?lat=${region.latitude}&long=${region.longitude}&lat_delta=${region.latitudeDelta}&long_delta=${region.longitudeDelta}`,
url: `${API_URL}/api/landmarks/`,
headers: { "Authorization": "Bearer " + authStore.accessToken, }
}
try {
const response = await axios(config);
return response.data;
} catch (error) {
if (error.response.status == 401) {
try {
await refreshAccessToken()
const response = await axios({...config, headers: { "Authorization": "Bearer " + authStore.accessToken }});
return response.data;
} catch (error) {
// refreshAccessToken will report errors
}
}
reportAxiosError('Something went wrong when retrieving landmarks', error)
throw new Error;
}
// }
// else {
// return [];
// }
}
/**
* The callback responsible for adding a new {@link Landmark} to the server, used by the [react-query useMutation]{@link https://react-query.tanstack.com/reference/useMutation#_top} hook.
* * @memberOf useLandmarks
*/
const createLandmark = async (landmarkValue: Landmark | undefined): Promise<Landmark | undefined> => {
const config: AxiosRequestConfig = {
method: 'POST',
data: landmarkValue,
url: API_URL + `/api/landmark/`,
headers: { "Authorization": "Bearer " + authStore.accessToken, }
}
try {
const response = await axios(config);
return response.data;
} catch (error) {
if (error.response.status == 401) {
try {
await refreshAccessToken()
const response = await axios({...config, headers: { "Authorization": "Bearer " + authStore.accessToken }});
return response.data;
} catch (error) {
// refreshAccessToken will report errors
}
}
reportAxiosError('Something went wrong when retrieving landmarks', error)
throw new Error;
}
}
/**
* The callback responsible for updating a {@link Landmark} on the server, used by the [react-query useMutation]{@link https://react-query.tanstack.com/reference/useMutation#_top} hook.
* * @memberOf useLandmarks
*/
const editLandmark = async (landmarkValue: Landmark) => {
const config: AxiosRequestConfig = {
method: 'PUT',
data: landmarkValue,
url: API_URL + `/api/landmark/`,
headers: { "Authorization": "Bearer " + authStore.accessToken, }
}
console.log(landmarkValue)
try {
const response = await axios(config);
return response.data;
} catch (error) {
if (error.response.status == 401) {
try {
await refreshAccessToken()
const response = await axios({...config, headers: { "Authorization": "Bearer " + authStore.accessToken }});
return response.data;
} catch (error) {
// refreshAccessToken will report errors
}
}
reportAxiosError('Something went wrong when retrieving landmarks', error)
throw new Error;
}
}
/**
* The callback responsible for deleting a {@link Landmark} from the server, used by the [react-query useMutation]{@link https://react-query.tanstack.com/reference/useMutation#_top} hook.
* * @memberOf useLandmarks
*/
const removeLandmark = async (id?: string | null) => {
const config: AxiosRequestConfig = {
method: 'DELETE',
url: API_URL + `/api/landmark/${id}`,
headers: { "Authorization": "Bearer " + authStore.accessToken, }
}
try {
const response = await axios(config);
return response.data;
} catch (error) {
if (error.response.status == 401) {
try {
await refreshAccessToken()
// add new access token to header
const response = await axios({...config, headers: {"Authorization": "Bearer " + authStore.accessToken}});
return response.data;
} catch (error) {
// refreshAccessToken will report errors
}
}
reportAxiosError('Something went wrong when retrieving landmarks', error)
throw new Error;
}
}
// get-all query
const { data: landmarks, status: getLandmarksStatus, refetch: refetchLandmarks } = useQuery<Landmark[], Error>(['getLandmarks', region], () => getLandmarks(region), {
placeholderData: () => queryClient.getQueryData('getLandmarks'),
staleTime: 1000,
refetchInterval: 30000,
refetchOnReconnect: true,
refetchOnMount: false
})
// mutations
const { status: addLandmarkStatus, mutateAsync: addLandmarkAsync, reset: resetAddLm, data: newLandmark } = useMutation(createLandmark, {
onSuccess: data => {
queryClient.invalidateQueries('getLandmarks')
},
})
const { status: updateLandmarkStatus, mutateAsync: updateLandmark, reset: resetUpdateLm } = useMutation(editLandmark, {
onSuccess: () => queryClient.invalidateQueries('getLandmarks'),
onError: () => queryClient.invalidateQueries('getLandmarks'),
})
const { status: deleteLandmarkStatus, mutateAsync: deleteLandmark, reset: resetDeleteLm } = useMutation(removeLandmark, {
onSuccess: () => queryClient.invalidateQueries('getLandmarks'),
onError: () => queryClient.invalidateQueries('getLandmarks'),
})
return {
landmarks, getLandmarksStatus, refetchLandmarks, //reading
addLandmarkAsync, resetAddLm, addLandmarkStatus, newLandmark, // creating
updateLandmark, resetUpdateLm, updateLandmarkStatus, // updating
deleteLandmark, resetDeleteLm, deleteLandmarkStatus, // deleting
}
}
Source