chore: refactor to remove duplication
issue #46 From now on, only a single getJSON function will be used to call the backend api. No more duplications
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import { API_TOKEN } from '../app-constants/app-constants';
|
||||
|
||||
const tokenState = localStorage.getItem(API_TOKEN);
|
||||
|
||||
function handleError(httpStatusCode: number) {
|
||||
if (httpStatusCode === 403) {
|
||||
throw new Error('Forbidden! Access denied');
|
||||
}
|
||||
if (httpStatusCode === 500) {
|
||||
throw new Error('Internal Server Error!');
|
||||
}
|
||||
throw new Error('Unknown error');
|
||||
}
|
||||
|
||||
const api = {
|
||||
getJSON: async (url: string) => {
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${tokenState}`
|
||||
}
|
||||
});
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} else {
|
||||
handleError(response.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default api;
|
||||
@@ -1,5 +1,6 @@
|
||||
import { API_TOKEN } from '../app-constants/app-constants';
|
||||
import { SigninResponse } from '../types/SigninResponse';
|
||||
import api from './api';
|
||||
import ApiConfig from './apiConfig';
|
||||
|
||||
/**
|
||||
@@ -88,41 +89,8 @@ function logoutUser(): void {
|
||||
localStorage.removeItem(API_TOKEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a GET request to the server to refresh the user token.
|
||||
*
|
||||
* @returns {Promise<SigninResponse>} A promise that resolves to SigninResponse if the request was
|
||||
* successful.
|
||||
* @throws {Error} An error object if there was an error
|
||||
*/
|
||||
async function refreshToken(): Promise<SigninResponse> {
|
||||
const tokenState = localStorage.getItem(API_TOKEN);
|
||||
|
||||
if (tokenState) {
|
||||
const response = await fetch(ApiConfig.refreshTokenUrl, {
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${tokenState}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
localStorage.setItem(API_TOKEN, data.token);
|
||||
return {
|
||||
token: data.token
|
||||
};
|
||||
}
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
throw new Error('No saved token!');
|
||||
}
|
||||
|
||||
export {
|
||||
registerUser,
|
||||
authenticateUser,
|
||||
logoutUser,
|
||||
refreshToken
|
||||
logoutUser
|
||||
};
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import { API_TOKEN } from '../app-constants/app-constants';
|
||||
import { HomeSearchResponse } from '../types/HomeSearchResponse';
|
||||
import { SummaryResponse } from '../types/SummaryResponse';
|
||||
import ApiConfig from './apiConfig';
|
||||
|
||||
/**
|
||||
* Sends a GET request to the server to get summaries for the home page.
|
||||
*
|
||||
* @returns {Promise<SummaryResponse>} A promise that resolves to SummaryResponse if the request
|
||||
* was successful.
|
||||
* @throws {Error} An error object if there was an error
|
||||
*/
|
||||
async function getHomeSummary(): Promise<SummaryResponse> {
|
||||
try {
|
||||
const tokenState = localStorage.getItem(API_TOKEN);
|
||||
const response = await fetch(`${ApiConfig.homeUrl}/summary`, {
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${tokenState}`
|
||||
}
|
||||
});
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
return data;
|
||||
}
|
||||
if (response.status === 403) {
|
||||
throw new Error('Forbidden! Access denied');
|
||||
}
|
||||
if (response.status === 500) {
|
||||
throw new Error('Internal Server Error!');
|
||||
}
|
||||
} catch (e) {
|
||||
if (typeof e === 'string') {
|
||||
throw new Error(e as string);
|
||||
}
|
||||
}
|
||||
throw new Error('Unknown error');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a GET request to the server to get summaries for the home page.
|
||||
*
|
||||
* @returns {Promise<HomeSearchResponse>} A promise that resolves to HomeSearchResponse if the
|
||||
* request was successful.
|
||||
* @throws {Error} An error object if there was an error
|
||||
*/
|
||||
async function searchHomeRequest(term: string): Promise<HomeSearchResponse> {
|
||||
try {
|
||||
const tokenState = localStorage.getItem(API_TOKEN);
|
||||
const response = await fetch(`${ApiConfig.homeUrl}/search?term=${term}`, {
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${tokenState}`
|
||||
}
|
||||
});
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
return data;
|
||||
}
|
||||
if (response.status === 403) {
|
||||
throw new Error('Forbidden! Access denied');
|
||||
}
|
||||
if (response.status === 500) {
|
||||
throw new Error('Internal Server Error!');
|
||||
}
|
||||
} catch (e) {
|
||||
if (typeof e === 'string') {
|
||||
throw new Error(e as string);
|
||||
}
|
||||
}
|
||||
throw new Error('Unknown error');
|
||||
}
|
||||
|
||||
export { getHomeSummary, searchHomeRequest };
|
||||
@@ -2,6 +2,7 @@ import { API_TOKEN } from '../app-constants/app-constants';
|
||||
import TaskNoteRequest from '../types/TaskNoteRequest';
|
||||
import { NoteResponse } from '../types/NoteResponse';
|
||||
import ApiConfig from './apiConfig';
|
||||
import api from './api';
|
||||
|
||||
/**
|
||||
* Sends a POST request to the server to create a note.
|
||||
@@ -43,42 +44,6 @@ async function addNoteRequest(note: TaskNoteRequest): Promise<NoteResponse> {
|
||||
throw new Error('Unknown error');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a GET request to the server to fetch all notes.
|
||||
*
|
||||
* @returns {Promise<NoteResponse[]>} A promise that resolves to an array of NoteResponse if the
|
||||
* request was successful.
|
||||
* @throws {Error} An error object if there was an error
|
||||
*/
|
||||
async function getNotesRequest(): Promise<NoteResponse[]> {
|
||||
try {
|
||||
const tokenState = localStorage.getItem(API_TOKEN);
|
||||
const response = await fetch(ApiConfig.notesUrl, {
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${tokenState}`
|
||||
}
|
||||
});
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
return data;
|
||||
}
|
||||
if (response.status === 403) {
|
||||
throw new Error('Forbidden! Access denied');
|
||||
}
|
||||
if (response.status === 500) {
|
||||
throw new Error('Internal Server Error!');
|
||||
}
|
||||
} catch (e) {
|
||||
if (typeof e === 'string') {
|
||||
throw new Error(e as string);
|
||||
}
|
||||
}
|
||||
throw new Error('Unknown error');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a PATCH request to the server to update a note.
|
||||
*
|
||||
@@ -157,5 +122,5 @@ async function deleteNoteRequest(id: number): Promise<undefined> {
|
||||
}
|
||||
|
||||
export {
|
||||
addNoteRequest, getNotesRequest, updateNoteRequest, deleteNoteRequest
|
||||
addNoteRequest, updateNoteRequest, deleteNoteRequest
|
||||
};
|
||||
|
||||
@@ -39,38 +39,6 @@ async function addTaskRequest(task: TaskNoteRequest): Promise<TaskResponse | Err
|
||||
throw new Error('Unknown error');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
async function getTasksRequest(): Promise<TaskResponse[]> {
|
||||
try {
|
||||
const tokenState = localStorage.getItem(API_TOKEN);
|
||||
const response = await fetch(ApiConfig.tasksUrl, {
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${tokenState}`
|
||||
}
|
||||
});
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
return data;
|
||||
}
|
||||
if (response.status === 403) {
|
||||
throw new Error('Forbidden! Access denied');
|
||||
}
|
||||
if (response.status === 500) {
|
||||
throw new Error('Internal Server Error!');
|
||||
}
|
||||
} catch (e) {
|
||||
if (typeof e === 'string') {
|
||||
throw new Error(e as string);
|
||||
}
|
||||
}
|
||||
throw new Error('Unknown error');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -136,5 +104,5 @@ async function deleteTaskRequest(id: number): Promise<undefined> {
|
||||
}
|
||||
|
||||
export {
|
||||
addTaskRequest, getTasksRequest, updateTaskDoneRequest, deleteTaskRequest
|
||||
addTaskRequest, updateTaskDoneRequest, deleteTaskRequest
|
||||
};
|
||||
|
||||
@@ -7,9 +7,10 @@ import { SigninResponse } from '../types/SigninResponse';
|
||||
import {
|
||||
authenticateUser,
|
||||
logoutUser,
|
||||
refreshToken,
|
||||
registerUser
|
||||
} from '../api-service/authService';
|
||||
import api from '../api-service/api';
|
||||
import ApiConfig from '../api-service/apiConfig';
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
@@ -23,10 +24,8 @@ const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }: Pro
|
||||
|
||||
const fetchCurrentSession = async (pathname: string): Promise<SigninResponse | undefined> => {
|
||||
try {
|
||||
const bearerToken: SigninResponse = await refreshToken();
|
||||
if (bearerToken && bearerToken.token) {
|
||||
setSigned(true);
|
||||
}
|
||||
const bearerToken: SigninResponse = await api.getJSON(ApiConfig.refreshTokenUrl);
|
||||
setSigned(true);
|
||||
return bearerToken;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
|
||||
@@ -5,11 +5,13 @@ import {
|
||||
Button, Card, Col, Container, Form, InputGroup, Row
|
||||
} from 'react-bootstrap';
|
||||
import './style.css';
|
||||
import { getHomeSummary, searchHomeRequest } from '../../api-service/homeService';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { SummaryResponse } from '../../types/SummaryResponse';
|
||||
import { HomeSearchResponse } from '../../types/HomeSearchResponse';
|
||||
import { TaskResponse } from '../../types/TaskResponse';
|
||||
import { NoteResponse } from '../../types/NoteResponse';
|
||||
import api from '../../api-service/api';
|
||||
import ApiConfig from '../../api-service/apiConfig';
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -20,6 +22,7 @@ function Home(): JSX.Element {
|
||||
const [validated, setValidated] = useState<boolean>(true);
|
||||
const [formInvalid, setFormInvalid] = useState<boolean>(false);
|
||||
const [searchResults, setSearchResults] = useState<HomeSearchResponse | null>(null);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleError = (e: unknown): void => {
|
||||
if (typeof e === 'string') {
|
||||
@@ -31,7 +34,7 @@ function Home(): JSX.Element {
|
||||
|
||||
const getSummary = async () => {
|
||||
try {
|
||||
const response = await getHomeSummary();
|
||||
const response = await api.getJSON(`${ApiConfig.homeUrl}/summary`);
|
||||
setSummary(response);
|
||||
} catch (e) {
|
||||
handleError(e);
|
||||
@@ -40,7 +43,7 @@ function Home(): JSX.Element {
|
||||
|
||||
const searchTerm = async (term: string): Promise<boolean> => {
|
||||
try {
|
||||
const response: HomeSearchResponse = await searchHomeRequest(term);
|
||||
const response: HomeSearchResponse = await api.getJSON(`${ApiConfig.homeUrl}/search?term=${term}`);
|
||||
setSearchResults(response);
|
||||
return true;
|
||||
} catch (e) {
|
||||
@@ -91,7 +94,11 @@ function Home(): JSX.Element {
|
||||
? 'Pending Tasks'
|
||||
: 'No pending tasks!'}
|
||||
</Card.Text>
|
||||
<Button variant="primary" href="/tasks">
|
||||
<Button
|
||||
variant="primary"
|
||||
type="button"
|
||||
onClick={() => navigate('/tasks')}
|
||||
>
|
||||
Go to Tasks
|
||||
</Button>
|
||||
</Card.Body>
|
||||
@@ -106,7 +113,11 @@ function Home(): JSX.Element {
|
||||
<Card.Body className="d-flex flex-column align-items-center justify-content-center">
|
||||
<Card.Title className="display-4">10</Card.Title>
|
||||
<Card.Text>Notes</Card.Text>
|
||||
<Button variant="success" href="/notes">
|
||||
<Button
|
||||
variant="success"
|
||||
type="button"
|
||||
onClick={() => navigate('/notes')}
|
||||
>
|
||||
Go to Notes
|
||||
</Button>
|
||||
</Card.Body>
|
||||
|
||||
@@ -7,8 +7,10 @@ import TaskNoteRequest from '../../types/TaskNoteRequest';
|
||||
import { NoteResponse } from '../../types/NoteResponse';
|
||||
import './style.css';
|
||||
import {
|
||||
addNoteRequest, deleteNoteRequest, getNotesRequest, updateNoteRequest
|
||||
addNoteRequest, deleteNoteRequest, updateNoteRequest
|
||||
} from '../../api-service/noteService';
|
||||
import api from '../../api-service/api';
|
||||
import ApiConfig from '../../api-service/apiConfig';
|
||||
|
||||
type NoteAction = 'add' | 'edit';
|
||||
|
||||
@@ -36,11 +38,11 @@ function Note(): JSX.Element {
|
||||
};
|
||||
|
||||
const loadNotes = async () => {
|
||||
const notesFetched: NoteResponse[] | Error = await getNotesRequest();
|
||||
if (notesFetched instanceof Error) {
|
||||
handleError(notesFetched);
|
||||
} else {
|
||||
try {
|
||||
const notesFetched: NoteResponse[] = await api.getJSON(ApiConfig.notesUrl);
|
||||
setNotes(notesFetched);
|
||||
} catch (e) {
|
||||
handleError(e);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -5,12 +5,13 @@ import {
|
||||
import {
|
||||
addTaskRequest,
|
||||
deleteTaskRequest,
|
||||
getTasksRequest,
|
||||
updateTaskDoneRequest
|
||||
} from '../../api-service/taskService';
|
||||
import TaskNoteRequest from '../../types/TaskNoteRequest';
|
||||
import { TaskResponse } from '../../types/TaskResponse';
|
||||
import './style.css';
|
||||
import api from '../../api-service/api';
|
||||
import ApiConfig from '../../api-service/apiConfig';
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -32,7 +33,7 @@ function Task(): JSX.Element {
|
||||
};
|
||||
|
||||
const loadTasks = async () => {
|
||||
const tasksFetched: TaskResponse[] | Error = await getTasksRequest();
|
||||
const tasksFetched: TaskResponse[] | Error = await api.getJSON(ApiConfig.tasksUrl);
|
||||
if (tasksFetched instanceof Error) {
|
||||
handleError(tasksFetched);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user