Use http wrapper instead of fetch

pull/3813/head
Kamran Ahmed 2 years ago
parent 0da417735e
commit a544cfea8d
  1. 48
      src/components/AuthenticationFlow/EmailLoginForm.tsx
  2. 60
      src/components/AuthenticationFlow/GitHubButton.tsx
  3. 49
      src/components/AuthenticationFlow/GoogleButton.tsx
  4. 28
      src/components/AuthenticationFlow/TriggerVerifyAccount.tsx
  5. 29
      src/components/AuthenticationFlow/VerificationEmailMessage.tsx
  6. 18
      src/hooks/use-auth.ts

@ -2,7 +2,7 @@ import Cookies from 'js-cookie';
import type { FunctionComponent } from 'preact'; import type { FunctionComponent } from 'preact';
import { useState } from 'preact/hooks'; import { useState } from 'preact/hooks';
import { httpPost } from '../../lib/http'; import { httpPost } from '../../lib/http';
import {TOKEN_COOKIE_NAME} from "../../lib/jwt"; import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
const EmailLoginForm: FunctionComponent<{}> = () => { const EmailLoginForm: FunctionComponent<{}> = () => {
const [email, setEmail] = useState<string>(''); const [email, setEmail] = useState<string>('');
@ -16,44 +16,32 @@ const EmailLoginForm: FunctionComponent<{}> = () => {
setIsLoading(true); setIsLoading(true);
setError(''); setError('');
fetch(`${import.meta.env.PUBLIC_API_URL}/v1-login`, { const { response, error } = await httpPost<{ token: string }>(
method: 'POST', `${import.meta.env.PUBLIC_API_URL}/v1-login`,
headers: { {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email, email,
password, password,
}), }
}) );
.then((res) => res.json())
.then((data) => { // Log the user in and reload the page
if (data.type === 'user_not_verified') { if (response?.token) {
window.location.href = `/verification-pending?email=${encodeURIComponent( Cookies.set(TOKEN_COOKIE_NAME, response.token);
email window.location.reload();
)}`;
return; return;
} }
if (!data.token) { // @todo use proper types
setIsLoading(false); if ((error as any).type === 'user_not_verified') {
setError( window.location.href = `/verification-pending?email=${encodeURIComponent(
data.message || 'Something went wrong. Please try again later.' email
); )}`;
return; return;
} }
// If the response is ok, we'll set the token in a cookie
Cookies.set(TOKEN_COOKIE_NAME, data.token);
// Refreshing will automatically redirect to the relevant page
// Doing this to avoid redirecting to home page from any pages
// such as roadmap, best-practice etc
window.location.reload();
})
.catch((err) => {
setIsLoading(false); setIsLoading(false);
setError('Something went wrong. Please try again later.'); setError(error?.message || 'Something went wrong. Please try again later.');
});
}; };
return ( return (

@ -4,6 +4,7 @@ import GitHubIcon from '../../icons/github.svg';
import SpinnerIcon from '../../icons/spinner.svg'; import SpinnerIcon from '../../icons/spinner.svg';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { TOKEN_COOKIE_NAME } from '../../lib/jwt'; import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
import { httpGet } from '../../lib/http';
type GitHubButtonProps = {}; type GitHubButtonProps = {};
@ -26,21 +27,20 @@ export function GitHubButton(props: GitHubButtonProps) {
} }
setIsLoading(true); setIsLoading(true);
fetch( httpGet<{ token: string }>(
`${import.meta.env.PUBLIC_API_URL}/v1-github-callback${ `${import.meta.env.PUBLIC_API_URL}/v1-github-callback${
window.location.search window.location.search
}`, }`
{
method: 'GET',
credentials: 'include',
}
) )
.then((res) => res.json()) .then(({ response, error }) => {
.then((data: any) => { if (!response?.token) {
if (!data.token) { const errMessage = error?.message || 'Something went wrong.';
setError('Something went wrong. Please try again later.'); setError(errMessage);
setIsLoading(false); setIsLoading(false);
} else {
return;
}
let redirectUrl = '/'; let redirectUrl = '/';
const gitHubRedirectAt = localStorage.getItem(GITHUB_REDIRECT_AT); const gitHubRedirectAt = localStorage.getItem(GITHUB_REDIRECT_AT);
const lastPageBeforeGithub = localStorage.getItem(GITHUB_LAST_PAGE); const lastPageBeforeGithub = localStorage.getItem(GITHUB_LAST_PAGE);
@ -59,9 +59,8 @@ export function GitHubButton(props: GitHubButtonProps) {
localStorage.removeItem(GITHUB_REDIRECT_AT); localStorage.removeItem(GITHUB_REDIRECT_AT);
localStorage.removeItem(GITHUB_LAST_PAGE); localStorage.removeItem(GITHUB_LAST_PAGE);
Cookies.set(TOKEN_COOKIE_NAME, data.token); Cookies.set(TOKEN_COOKIE_NAME, response.token);
window.location.href = redirectUrl; window.location.href = redirectUrl;
}
}) })
.catch((err) => { .catch((err) => {
setError('Something went wrong. Please try again later.'); setError('Something went wrong. Please try again later.');
@ -69,16 +68,22 @@ export function GitHubButton(props: GitHubButtonProps) {
}); });
}, []); }, []);
const handleClick = () => { const handleClick = async () => {
setIsLoading(true); setIsLoading(true);
fetch(`${import.meta.env.PUBLIC_API_URL}/v1-github-login`, {
credentials: 'include', const { response, error } = await httpGet<{ loginUrl: string }>(
redirect: 'follow', `${import.meta.env.PUBLIC_API_URL}/v1-github-login`
}) );
.then((res) => res.json())
.then((data: any) => { if (error || !response?.loginUrl) {
// @todo proper typing for API response setError(
if (data.loginUrl) { error?.message || 'Something went wrong. Please try again later.'
);
setIsLoading(false);
return;
}
// For non authentication pages, we want to redirect back to the page // For non authentication pages, we want to redirect back to the page
// the user was on before they clicked the social login button // the user was on before they clicked the social login button
if (!['/login', '/signup'].includes(window.location.pathname)) { if (!['/login', '/signup'].includes(window.location.pathname)) {
@ -86,16 +91,7 @@ export function GitHubButton(props: GitHubButtonProps) {
localStorage.setItem(GITHUB_LAST_PAGE, window.location.pathname); localStorage.setItem(GITHUB_LAST_PAGE, window.location.pathname);
} }
window.location.href = data.loginUrl; window.location.href = response.loginUrl;
} else {
setError('Something went wrong. Please try again later.');
setIsLoading(false);
}
})
.catch((err) => {
setError('Something went wrong. Please try again later.');
setIsLoading(false);
});
}; };
return ( return (

@ -3,6 +3,7 @@ import Cookies from 'js-cookie';
import GoogleIcon from '../../icons/google.svg'; import GoogleIcon from '../../icons/google.svg';
import SpinnerIcon from '../../icons/spinner.svg'; import SpinnerIcon from '../../icons/spinner.svg';
import { TOKEN_COOKIE_NAME } from '../../lib/jwt'; import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
import { httpGet } from '../../lib/http';
type GoogleButtonProps = {}; type GoogleButtonProps = {};
@ -25,21 +26,19 @@ export function GoogleButton(props: GoogleButtonProps) {
} }
setIsLoading(true); setIsLoading(true);
fetch( httpGet<{ token: string }>(
`${import.meta.env.PUBLIC_API_URL}/v1-google-callback${ `${import.meta.env.PUBLIC_API_URL}/v1-google-callback${
window.location.search window.location.search
}`, }`
{
method: 'GET',
credentials: 'include',
}
) )
.then((res) => res.json()) .then(({ response, error }) => {
.then((data: any) => { if (!response?.token) {
if (!data.token) { setError(error?.message || 'Something went wrong.');
setError('Something went wrong. Please try again later.');
setIsLoading(false); setIsLoading(false);
} else {
return;
}
let redirectUrl = '/'; let redirectUrl = '/';
const googleRedirectAt = localStorage.getItem(GOOGLE_REDIRECT_AT); const googleRedirectAt = localStorage.getItem(GOOGLE_REDIRECT_AT);
const lastPageBeforeGoogle = localStorage.getItem(GOOGLE_LAST_PAGE); const lastPageBeforeGoogle = localStorage.getItem(GOOGLE_LAST_PAGE);
@ -58,9 +57,8 @@ export function GoogleButton(props: GoogleButtonProps) {
localStorage.removeItem(GOOGLE_REDIRECT_AT); localStorage.removeItem(GOOGLE_REDIRECT_AT);
localStorage.removeItem(GOOGLE_LAST_PAGE); localStorage.removeItem(GOOGLE_LAST_PAGE);
Cookies.set(TOKEN_COOKIE_NAME, data.token); Cookies.set(TOKEN_COOKIE_NAME, response.token);
window.location.href = redirectUrl; window.location.href = redirectUrl;
}
}) })
.catch((err) => { .catch((err) => {
setError('Something went wrong. Please try again later.'); setError('Something went wrong. Please try again later.');
@ -70,14 +68,17 @@ export function GoogleButton(props: GoogleButtonProps) {
const handleClick = () => { const handleClick = () => {
setIsLoading(true); setIsLoading(true);
fetch(`${import.meta.env.PUBLIC_API_URL}/v1-google-login`, { httpGet<{ loginUrl: string }>(
credentials: 'include', `${import.meta.env.PUBLIC_API_URL}/v1-google-login`
redirect: 'follow', )
}) .then(({ response, error }) => {
.then((res) => res.json()) if (!response?.loginUrl) {
.then((data: any) => { setError(error?.message || 'Something went wrong.');
// @todo proper typing for API response setIsLoading(false);
if (data.loginUrl) {
return;
}
// For non authentication pages, we want to redirect back to the page // For non authentication pages, we want to redirect back to the page
// the user was on before they clicked the social login button // the user was on before they clicked the social login button
if (!['/login', '/signup'].includes(window.location.pathname)) { if (!['/login', '/signup'].includes(window.location.pathname)) {
@ -85,11 +86,7 @@ export function GoogleButton(props: GoogleButtonProps) {
localStorage.setItem(GOOGLE_LAST_PAGE, window.location.pathname); localStorage.setItem(GOOGLE_LAST_PAGE, window.location.pathname);
} }
window.location.href = data.loginUrl; window.location.href = response.loginUrl;
} else {
setError('Something went wrong. Please try again later.');
setIsLoading(false);
}
}) })
.catch((err) => { .catch((err) => {
setError('Something went wrong. Please try again later.'); setError('Something went wrong. Please try again later.');

@ -3,7 +3,8 @@ import ErrorIcon from '../../icons/error.svg';
import { useEffect, useState } from 'preact/hooks'; import { useEffect, useState } from 'preact/hooks';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import {TOKEN_COOKIE_NAME} from "../../lib/jwt"; import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
import { httpPost } from '../../lib/http';
export function TriggerVerifyAccount() { export function TriggerVerifyAccount() {
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
@ -12,22 +13,21 @@ export function TriggerVerifyAccount() {
const triggerVerify = (code: string) => { const triggerVerify = (code: string) => {
setIsLoading(true); setIsLoading(true);
fetch(`${import.meta.env.PUBLIC_API_URL}/v1-verify-account`, { httpPost<{ token: string }>(
method: 'POST', `${import.meta.env.PUBLIC_API_URL}/v1-verify-account`,
headers: { {
'Content-Type': 'application/json',
},
body: JSON.stringify({
code, code,
}), }
}) )
.then((res) => res.json()) .then(({ response, error }) => {
.then((data: any) => { if (!response?.token) {
if (!data.token) { setError(error?.message || 'Something went wrong. Please try again.');
throw new Error('Something went wrong. Please try again..'); setIsLoading(false);
return;
} }
Cookies.set(TOKEN_COOKIE_NAME, data.token); Cookies.set(TOKEN_COOKIE_NAME, response.token);
window.location.href = '/'; window.location.href = '/';
}) })
.catch((err) => { .catch((err) => {

@ -1,5 +1,6 @@
import VerifyLetterIcon from '../../icons/verify-letter.svg'; import VerifyLetterIcon from '../../icons/verify-letter.svg';
import { useEffect, useState } from 'preact/hooks'; import { useEffect, useState } from 'preact/hooks';
import { httpPost } from '../../lib/http';
export function VerificationEmailMessage() { export function VerificationEmailMessage() {
const [email, setEmail] = useState('..'); const [email, setEmail] = useState('..');
@ -14,18 +15,15 @@ export function VerificationEmailMessage() {
}, []); }, []);
const resendVerificationEmail = () => { const resendVerificationEmail = () => {
fetch(`${import.meta.env.PUBLIC_API_URL}/v1-send-verification-email`, { httpPost(`${import.meta.env.PUBLIC_API_URL}/v1-send-verification-email`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email, email,
}),
}) })
.then((res) => { .then(({ response, error }) => {
if (!res.ok) { if (error) {
throw new Error('Something went wrong. Please try again later.'); setIsEmailResent(false);
setError(error?.message || 'Something went wrong.');
setIsLoading(false);
return;
} }
setIsEmailResent(true); setIsEmailResent(true);
@ -49,9 +47,10 @@ export function VerificationEmailMessage() {
</h2> </h2>
<div class="text-sm sm:text-base"> <div class="text-sm sm:text-base">
<p> <p>
We have sent you an email at <span className="font-bold">{email}</span>. We have sent you an email at{' '}
Please click the link to verify your account. This link will expire <span className="font-bold">{email}</span>. Please click the link to
shortly, so please verify soon! verify your account. This link will expire shortly, so please verify
soon!
</p> </p>
<hr class="my-4" /> <hr class="my-4" />
@ -77,7 +76,9 @@ export function VerificationEmailMessage() {
</> </>
)} )}
{isEmailResent && <p class="text-green-700">Verification email has been sent!</p>} {isEmailResent && (
<p class="text-green-700">Verification email has been sent!</p>
)}
</div> </div>
</div> </div>
); );

@ -1,18 +0,0 @@
import { useEffect, useState } from 'preact/hooks';
import {TokenPayload, decodeToken, TOKEN_COOKIE_NAME} from '../lib/jwt';
import Cookies from 'js-cookie';
export const useAuth = () => {
const [user, setUser] = useState<TokenPayload | null>(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const token = Cookies.get(TOKEN_COOKIE_NAME);
const payload = token ? decodeToken(token) : null;
setUser(payload);
setIsLoading(false);
}, []);
return { user, isLoading };
};
Loading…
Cancel
Save