* wip: custom roadmap renderer * wip: custom roadmap events * wip: roadmap content * wip: svg styles * wip: custom roadmap progress * Render progress * Shortcut progress * Progress Tracking styles * wip: edit and share button * fix: disabled the share button * wip: content links rendering * Fix progress share * Replace disabled with `canShare` * wip: show custom roadmaps * wip: users all roadmaps * fix: create roadmap api * chore: roadmap sidebar icon * wip: content links * Update links color * Create roadmap home * Create Roadmap button * Roadmap type * chore: share progress modal * wip: share roadmap * wip: change visibility * chore: custom roadmap progress in activity * wip: custom roadmap share progress * chore: friend's roadmap * wip: custom roadmap skeleton * chore: roadmap title * Restricted Page * fix: skeleton loading width * Fix create roadmap button * chore: remove user id * chore: pick roadmap and share * chore: open new tab on create roadmap * chore: change share title * chore: use team id from params * chore: team roadmap create modal * chore: create team roadmap * chore: custom roadmap modal * chore: placeholde roadmaps * chore: roadmap hint * chore: visibility label * chore: public roadmap * chore: empty screen * chore: team progress * chore: create roadmap responsive * chore: form error * chore: multi user history * wip: manage custom roadmap * chore: empty roadmap list * chore: custom roadmap visit * chore: shared roadmaps * chore: shared roadmaps * chore: empty screen and topic title * chore: show progress bar * Implement Error in topic details * Add Modal close button * fix: link groups * Refactor roadmap creation * Refactor roadmap creation * Refactor team creation * Refactor team roadmaps * Refactor team creation roadmap selection * Refactor * Refactor team roadmap loading * Refactor team roadmaps * Refactor team roadmaps listing * Refactor Account dropdown * Updates * Refactor Account dropdown * Fix Team name overflow * Change Icon color * Update team dropdown * Minor UI fixes * Fix minor UI * Flicker fix in team dropdown * Roadmap action dropdown with responsiveness * Team roadmaps listing * Update team settings * Team roadmaps listing * fix: remove visibility change * Update roadmap options modal * Add dummy renderer * Add renderer script * Add generate renderer script * Add generate renderer * wip: add share settings * Update * Update UI * Update Minor UI * Fix team issue * Update Personal roadmaps UI * Add Roadmap Secret * Update teams type * Rearrange sections * Change Secret name * Add action button on roadmap detail page --------- Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
162 lines
3.9 KiB
TypeScript
162 lines
3.9 KiB
TypeScript
import Cookies from 'js-cookie';
|
|
import fp from '@fingerprintjs/fingerprintjs';
|
|
import { TOKEN_COOKIE_NAME } from './jwt';
|
|
|
|
type HttpOptionsType = RequestInit | { headers: Record<string, any> };
|
|
|
|
type AppResponse = Record<string, any>;
|
|
|
|
export type FetchError = {
|
|
status: number;
|
|
message: string;
|
|
};
|
|
|
|
export type AppError = {
|
|
status: number;
|
|
message: string;
|
|
errors?: { message: string; location: string }[];
|
|
};
|
|
|
|
type ApiReturn<ResponseType, ErrorType> = {
|
|
response?: ResponseType;
|
|
error?: ErrorType | FetchError;
|
|
};
|
|
|
|
/**
|
|
* Wrapper around fetch to make it easy to handle errors
|
|
*
|
|
* @param url
|
|
* @param options
|
|
*/
|
|
export async function httpCall<
|
|
ResponseType = AppResponse,
|
|
ErrorType = AppError
|
|
>(
|
|
url: string,
|
|
options?: HttpOptionsType
|
|
): Promise<ApiReturn<ResponseType, ErrorType>> {
|
|
try {
|
|
const fingerprintPromise = await fp.load({ monitoring: false });
|
|
const fingerprint = await fingerprintPromise.get();
|
|
|
|
const response = await fetch(url, {
|
|
credentials: 'include',
|
|
...options,
|
|
headers: new Headers({
|
|
'Content-Type': 'application/json',
|
|
Accept: 'application/json',
|
|
Authorization: `Bearer ${Cookies.get(TOKEN_COOKIE_NAME)}`,
|
|
fp: fingerprint.visitorId,
|
|
...(options?.headers ?? {}),
|
|
}),
|
|
});
|
|
|
|
// @ts-ignore
|
|
const doesAcceptHtml = options?.headers?.['Accept'] === 'text/html';
|
|
|
|
const data = doesAcceptHtml ? await response.text() : await response.json();
|
|
|
|
if (response.ok) {
|
|
return {
|
|
response: data as ResponseType,
|
|
error: undefined,
|
|
};
|
|
}
|
|
|
|
// Logout user if token is invalid
|
|
if (data.status === 401) {
|
|
Cookies.remove(TOKEN_COOKIE_NAME);
|
|
window.location.reload();
|
|
return { response: undefined, error: data as ErrorType };
|
|
}
|
|
|
|
if (data.status === 403) {
|
|
// window.location.href = '/account'; // @fixme redirect option should be configurable
|
|
return { response: undefined, error: data as ErrorType };
|
|
}
|
|
|
|
return {
|
|
response: undefined,
|
|
error: data as ErrorType,
|
|
};
|
|
} catch (error: any) {
|
|
return {
|
|
response: undefined,
|
|
error: {
|
|
status: 0,
|
|
message: error.message,
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
export async function httpPost<
|
|
ResponseType = AppResponse,
|
|
ErrorType = AppError
|
|
>(
|
|
url: string,
|
|
body: Record<string, any>,
|
|
options?: HttpOptionsType
|
|
): Promise<ApiReturn<ResponseType, ErrorType>> {
|
|
return httpCall<ResponseType, ErrorType>(url, {
|
|
...options,
|
|
method: 'POST',
|
|
body: JSON.stringify(body),
|
|
});
|
|
}
|
|
|
|
export async function httpGet<ResponseType = AppResponse, ErrorType = AppError>(
|
|
url: string,
|
|
queryParams?: Record<string, any>,
|
|
options?: HttpOptionsType
|
|
): Promise<ApiReturn<ResponseType, ErrorType>> {
|
|
const searchParams = new URLSearchParams(queryParams).toString();
|
|
const queryUrl = searchParams ? `${url}?${searchParams}` : url;
|
|
|
|
return httpCall<ResponseType, ErrorType>(queryUrl, {
|
|
credentials: 'include',
|
|
method: 'GET',
|
|
...options,
|
|
});
|
|
}
|
|
|
|
export async function httpPatch<
|
|
ResponseType = AppResponse,
|
|
ErrorType = AppError
|
|
>(
|
|
url: string,
|
|
body: Record<string, any>,
|
|
options?: HttpOptionsType
|
|
): Promise<ApiReturn<ResponseType, ErrorType>> {
|
|
return httpCall<ResponseType, ErrorType>(url, {
|
|
...options,
|
|
method: 'PATCH',
|
|
body: JSON.stringify(body),
|
|
});
|
|
}
|
|
|
|
export async function httpPut<ResponseType = AppResponse, ErrorType = AppError>(
|
|
url: string,
|
|
body: Record<string, any>,
|
|
options?: HttpOptionsType
|
|
): Promise<ApiReturn<ResponseType, ErrorType>> {
|
|
return httpCall<ResponseType, ErrorType>(url, {
|
|
...options,
|
|
method: 'PUT',
|
|
body: JSON.stringify(body),
|
|
});
|
|
}
|
|
|
|
export async function httpDelete<
|
|
ResponseType = AppResponse,
|
|
ErrorType = AppError
|
|
>(
|
|
url: string,
|
|
options?: HttpOptionsType
|
|
): Promise<ApiReturn<ResponseType, ErrorType>> {
|
|
return httpCall<ResponseType, ErrorType>(url, {
|
|
...options,
|
|
method: 'DELETE',
|
|
});
|
|
}
|