* feat: integrate astro * chore: login popup design * chore: data-popup changed * refactor: github and google button * chore: signup page * chore: login popup design * chore: signup page design * chore: auth divider * feat: integrate astro * chore: login popup design * chore: data-popup changed * refactor: github and google button * chore: signup page * chore: login popup design * chore: signup page design * chore: auth divider * chore: login feature * chore: login error message * chore: added name in token decode return * chore: use auth hook * chore: logout vs login * chore: download button link * chore: account dropdown * fix: dropdown z index * chore: profile page * Add missing content for backend roadmap * Remove unused styles * Add login with google * chore: google login implementation * chore: profile guard clause * fix: button size * chore: preact to astro components * chore: preact to astro comp * chore: github astro component * chore: google login error handling * chore: github login error handling * chore: change password page * chore: rename profile to password * fix: change password rename * chore: update profile page * chore: setting sidebar * fix: setting dropdown design * chore: required indicator * chore: change password form * chore: update profile form * chore: mobile navigation * fix: form data empty error * chore: email login and signup components * chore: forgot password page * chore: reset password page * chore: verify account page * chore: resend verification email * fix: types in spinner * chore: forgot password functionality * fix: class -> className * chore: reset password page * chore: reset password functionality * chore: login page * fix: spacing for login and signup page * refactor: email login form * chore: astro spinner * chore: pre-fill user data * chore: dummy placeholder * chore: forgot password link add * fix: replaced constants * chore: forgot password link * chore: change password for social provider * chore: internal pages guard * chore: internal paths * refactor: change password errors * refactor: update profile errors * chore: mark as done overlay * fix: uncontrolled to controlled form * fix: de-structure error * chore: error messages * fix: 401 error code redirect to login page * chore: loading spinner accessibilities * fix: remove spinner * chore: keep spinner after success to redirect * chore: keep the spinner * style: resend email underline * chore: chevron down account * chore: roadmap pdf link download * chore: roadmap pdf link download * chore: best practices buttons * fix: verify account text * fix: topic overlay hide * chore: base verify design * chore: email verify page * fix: div tag missing * Formatting * Refactor top navigation * Prettier * Update dependencies * Refactor top navigation * Refactor login button * Remove captcha and add google scripts * Refactor email sign up form * Resend verfication email functionality * Refactor verification pending page * Add verify account functionality * Update signup text * Add login page * Add login button in top nav * Email login form * Handle authenticatoin * Show hide auth elements change * Add ease-in on the guest elements * Refactor logic for download and subscribe popups * Add forgot password * Rename fetch lib * Add authentication popup * Refactor logic for mark done and pending * Handle logout * Add route protection * Popup opener to close the overlay * Remember page when logging in * Add reset password page * Change placement of constant * Update profile page * Add update password form * Update password page * Update profile page * Update design * chore: toggle mark resource done api * chore: toggle topic done * chore: get user resource progress api * fix: best practice topic toggle * chore: fetch progress * fix: query selector for topics * Keep track of the old page before social login * Update public api url * Add user progress tracking * Update topic done functionality * Add progress loader * Add page wide spinner * Add spinner on setting pages * Add fingerprint to user requests * Use http wrapper instead of fetch * Update fingerprint * Minor improvements --------- Co-authored-by: Arik Chakma <arikchangma@gmail.com>
154 lines
3.6 KiB
TypeScript
154 lines
3.6 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>;
|
|
type FetchError = {
|
|
status: number;
|
|
message: string;
|
|
};
|
|
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,
|
|
};
|
|
} 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',
|
|
});
|
|
}
|