Skip to content

Commit 8850655

Browse files
Merge pull request #121 from kamranahmedse/master
Create a new pull request by comparing changes across two branches
2 parents 4983567 + 7ba4852 commit 8850655

File tree

50 files changed

+3273
-84
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+3273
-84
lines changed

public/pdfs/roadmaps/mlops.pdf

41.6 KB
Binary file not shown.

public/roadmaps/mlops.png

288 KB
Loading
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { useState } from 'react';
2+
import { GitHubButton } from './GitHubButton';
3+
import { GoogleButton } from './GoogleButton';
4+
import { LinkedInButton } from './LinkedInButton';
5+
import { EmailLoginForm } from './EmailLoginForm';
6+
import { EmailSignupForm } from './EmailSignupForm';
7+
8+
type AuthenticationFormProps = {
9+
type?: 'login' | 'signup';
10+
};
11+
12+
export function AuthenticationForm(props: AuthenticationFormProps) {
13+
const { type = 'login' } = props;
14+
15+
const [isDisabled, setIsDisabled] = useState(false);
16+
17+
return (
18+
<>
19+
<div className="flex w-full flex-col gap-2">
20+
<GitHubButton isDisabled={isDisabled} setIsDisabled={setIsDisabled} />
21+
<GoogleButton isDisabled={isDisabled} setIsDisabled={setIsDisabled} />
22+
<LinkedInButton isDisabled={isDisabled} setIsDisabled={setIsDisabled} />
23+
</div>
24+
25+
<div className="flex w-full items-center gap-2 py-6 text-sm text-slate-600">
26+
<div className="h-px w-full bg-slate-200" />
27+
OR
28+
<div className="h-px w-full bg-slate-200" />
29+
</div>
30+
31+
{type === 'login' ? (
32+
<EmailLoginForm isDisabled={isDisabled} setIsDisabled={setIsDisabled} />
33+
) : (
34+
<EmailSignupForm
35+
isDisabled={isDisabled}
36+
setIsDisabled={setIsDisabled}
37+
/>
38+
)}
39+
</>
40+
);
41+
}

src/components/AuthenticationFlow/EmailLoginForm.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@ import { useState } from 'react';
44
import { httpPost } from '../../lib/http';
55
import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
66

7-
export function EmailLoginForm() {
7+
type EmailLoginFormProps = {
8+
isDisabled?: boolean;
9+
setIsDisabled?: (isDisabled: boolean) => void;
10+
};
11+
12+
export function EmailLoginForm(props: EmailLoginFormProps) {
13+
const { isDisabled, setIsDisabled } = props;
14+
815
const [email, setEmail] = useState<string>('');
916
const [password, setPassword] = useState<string>('');
1017
const [error, setError] = useState('');
@@ -14,6 +21,7 @@ export function EmailLoginForm() {
1421
const handleFormSubmit = async (e: FormEvent<HTMLFormElement>) => {
1522
e.preventDefault();
1623
setIsLoading(true);
24+
setIsDisabled?.(true);
1725
setError('');
1826

1927
const { response, error } = await httpPost<{ token: string }>(
@@ -45,6 +53,7 @@ export function EmailLoginForm() {
4553
}
4654

4755
setIsLoading(false);
56+
setIsDisabled?.(false);
4857
setError(error?.message || 'Something went wrong. Please try again later.');
4958
};
5059

@@ -92,7 +101,7 @@ export function EmailLoginForm() {
92101

93102
<button
94103
type="submit"
95-
disabled={isLoading}
104+
disabled={isLoading || isDisabled}
96105
className="inline-flex w-full items-center justify-center rounded-lg bg-black p-2 py-3 text-sm font-medium text-white outline-none focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:bg-gray-400"
97106
>
98107
{isLoading ? 'Please wait...' : 'Continue'}

src/components/AuthenticationFlow/EmailSignupForm.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { type FormEvent, useState } from 'react';
22
import { httpPost } from '../../lib/http';
33

4-
export function EmailSignupForm() {
4+
type EmailSignupFormProps = {
5+
isDisabled?: boolean;
6+
setIsDisabled?: (isDisabled: boolean) => void;
7+
};
8+
9+
export function EmailSignupForm(props: EmailSignupFormProps) {
10+
const { isDisabled, setIsDisabled } = props;
11+
512
const [email, setEmail] = useState('');
613
const [password, setPassword] = useState('');
714
const [name, setName] = useState('');
@@ -13,6 +20,7 @@ export function EmailSignupForm() {
1320
e.preventDefault();
1421

1522
setIsLoading(true);
23+
setIsDisabled?.(true);
1624
setError('');
1725

1826
const { response, error } = await httpPost<{ status: 'ok' }>(
@@ -21,20 +29,21 @@ export function EmailSignupForm() {
2129
email,
2230
password,
2331
name,
24-
}
32+
},
2533
);
2634

2735
if (error || response?.status !== 'ok') {
2836
setIsLoading(false);
37+
setIsDisabled?.(false);
2938
setError(
30-
error?.message || 'Something went wrong. Please try again later.'
39+
error?.message || 'Something went wrong. Please try again later.',
3140
);
3241

3342
return;
3443
}
3544

3645
window.location.href = `/verification-pending?email=${encodeURIComponent(
37-
email
46+
email,
3847
)}`;
3948
};
4049

@@ -90,7 +99,7 @@ export function EmailSignupForm() {
9099

91100
<button
92101
type="submit"
93-
disabled={isLoading}
102+
disabled={isLoading || isDisabled}
94103
className="inline-flex w-full items-center justify-center rounded-lg bg-black p-2 py-3 text-sm font-medium text-white outline-none focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:bg-gray-400"
95104
>
96105
{isLoading ? 'Please wait...' : 'Continue to Verify Email'}

src/components/AuthenticationFlow/GitHubButton.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@ import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
55
import { httpGet } from '../../lib/http';
66
import { Spinner } from '../ReactIcons/Spinner.tsx';
77

8-
type GitHubButtonProps = {};
8+
type GitHubButtonProps = {
9+
isDisabled?: boolean;
10+
setIsDisabled?: (isDisabled: boolean) => void;
11+
};
912

1013
const GITHUB_REDIRECT_AT = 'githubRedirectAt';
1114
const GITHUB_LAST_PAGE = 'githubLastPage';
1215

1316
export function GitHubButton(props: GitHubButtonProps) {
17+
const { isDisabled, setIsDisabled } = props;
18+
1419
const [isLoading, setIsLoading] = useState(false);
1520
const [error, setError] = useState('');
1621

@@ -25,6 +30,7 @@ export function GitHubButton(props: GitHubButtonProps) {
2530
}
2631

2732
setIsLoading(true);
33+
setIsDisabled?.(true);
2834
httpGet<{ token: string }>(
2935
`${import.meta.env.PUBLIC_API_URL}/v1-github-callback${
3036
window.location.search
@@ -35,6 +41,7 @@ export function GitHubButton(props: GitHubButtonProps) {
3541
const errMessage = error?.message || 'Something went wrong.';
3642
setError(errMessage);
3743
setIsLoading(false);
44+
setIsDisabled?.(false);
3845

3946
return;
4047
}
@@ -73,11 +80,13 @@ export function GitHubButton(props: GitHubButtonProps) {
7380
.catch((err) => {
7481
setError('Something went wrong. Please try again later.');
7582
setIsLoading(false);
83+
setIsDisabled?.(false);
7684
});
7785
}, []);
7886

7987
const handleClick = async () => {
8088
setIsLoading(true);
89+
setIsDisabled?.(true);
8190

8291
const { response, error } = await httpGet<{ loginUrl: string }>(
8392
`${import.meta.env.PUBLIC_API_URL}/v1-github-login`,
@@ -89,6 +98,7 @@ export function GitHubButton(props: GitHubButtonProps) {
8998
);
9099

91100
setIsLoading(false);
101+
setIsDisabled?.(false);
92102
return;
93103
}
94104

@@ -112,7 +122,7 @@ export function GitHubButton(props: GitHubButtonProps) {
112122
<>
113123
<button
114124
className="inline-flex h-10 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white p-2 text-sm font-medium text-black outline-none focus:ring-2 focus:ring-[#333] focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60"
115-
disabled={isLoading}
125+
disabled={isLoading || isDisabled}
116126
onClick={handleClick}
117127
>
118128
{isLoading ? (

src/components/AuthenticationFlow/GoogleButton.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@ import { httpGet } from '../../lib/http';
55
import { Spinner } from '../ReactIcons/Spinner.tsx';
66
import { GoogleIcon } from '../ReactIcons/GoogleIcon.tsx';
77

8-
type GoogleButtonProps = {};
8+
type GoogleButtonProps = {
9+
isDisabled?: boolean;
10+
setIsDisabled?: (isDisabled: boolean) => void;
11+
};
912

1013
const GOOGLE_REDIRECT_AT = 'googleRedirectAt';
1114
const GOOGLE_LAST_PAGE = 'googleLastPage';
1215

1316
export function GoogleButton(props: GoogleButtonProps) {
17+
const { isDisabled, setIsDisabled } = props;
18+
1419
const [isLoading, setIsLoading] = useState(false);
1520
const [error, setError] = useState('');
1621

@@ -25,6 +30,7 @@ export function GoogleButton(props: GoogleButtonProps) {
2530
}
2631

2732
setIsLoading(true);
33+
setIsDisabled?.(true);
2834
httpGet<{ token: string }>(
2935
`${import.meta.env.PUBLIC_API_URL}/v1-google-callback${
3036
window.location.search
@@ -34,6 +40,7 @@ export function GoogleButton(props: GoogleButtonProps) {
3440
if (!response?.token) {
3541
setError(error?.message || 'Something went wrong.');
3642
setIsLoading(false);
43+
setIsDisabled?.(false);
3744

3845
return;
3946
}
@@ -72,18 +79,21 @@ export function GoogleButton(props: GoogleButtonProps) {
7279
.catch((err) => {
7380
setError('Something went wrong. Please try again later.');
7481
setIsLoading(false);
82+
setIsDisabled?.(false);
7583
});
7684
}, []);
7785

7886
const handleClick = () => {
7987
setIsLoading(true);
88+
setIsDisabled?.(true);
8089
httpGet<{ loginUrl: string }>(
8190
`${import.meta.env.PUBLIC_API_URL}/v1-google-login`,
8291
)
8392
.then(({ response, error }) => {
8493
if (!response?.loginUrl) {
8594
setError(error?.message || 'Something went wrong.');
8695
setIsLoading(false);
96+
setIsDisabled?.(false);
8797

8898
return;
8999
}
@@ -106,14 +116,15 @@ export function GoogleButton(props: GoogleButtonProps) {
106116
.catch((err) => {
107117
setError('Something went wrong. Please try again later.');
108118
setIsLoading(false);
119+
setIsDisabled?.(false);
109120
});
110121
};
111122

112123
return (
113124
<>
114125
<button
115126
className="inline-flex h-10 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white p-2 text-sm font-medium text-black outline-none focus:ring-2 focus:ring-[#333] focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60"
116-
disabled={isLoading}
127+
disabled={isLoading || isDisabled}
117128
onClick={handleClick}
118129
>
119130
{isLoading ? (

src/components/AuthenticationFlow/LinkedInButton.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@ import { httpGet } from '../../lib/http';
55
import { Spinner } from '../ReactIcons/Spinner.tsx';
66
import { LinkedInIcon } from '../ReactIcons/LinkedInIcon.tsx';
77

8-
type LinkedInButtonProps = {};
8+
type LinkedInButtonProps = {
9+
isDisabled?: boolean;
10+
setIsDisabled?: (isDisabled: boolean) => void;
11+
};
912

1013
const LINKEDIN_REDIRECT_AT = 'linkedInRedirectAt';
1114
const LINKEDIN_LAST_PAGE = 'linkedInLastPage';
1215

1316
export function LinkedInButton(props: LinkedInButtonProps) {
17+
const { isDisabled, setIsDisabled } = props;
18+
1419
const [isLoading, setIsLoading] = useState(false);
1520
const [error, setError] = useState('');
1621

@@ -25,6 +30,7 @@ export function LinkedInButton(props: LinkedInButtonProps) {
2530
}
2631

2732
setIsLoading(true);
33+
setIsDisabled?.(true);
2834
httpGet<{ token: string }>(
2935
`${import.meta.env.PUBLIC_API_URL}/v1-linkedin-callback${
3036
window.location.search
@@ -34,6 +40,7 @@ export function LinkedInButton(props: LinkedInButtonProps) {
3440
if (!response?.token) {
3541
setError(error?.message || 'Something went wrong.');
3642
setIsLoading(false);
43+
setIsDisabled?.(false);
3744

3845
return;
3946
}
@@ -72,18 +79,21 @@ export function LinkedInButton(props: LinkedInButtonProps) {
7279
.catch((err) => {
7380
setError('Something went wrong. Please try again later.');
7481
setIsLoading(false);
82+
setIsDisabled?.(false);
7583
});
7684
}, []);
7785

7886
const handleClick = () => {
7987
setIsLoading(true);
88+
setIsDisabled?.(true);
8089
httpGet<{ loginUrl: string }>(
8190
`${import.meta.env.PUBLIC_API_URL}/v1-linkedin-login`,
8291
)
8392
.then(({ response, error }) => {
8493
if (!response?.loginUrl) {
8594
setError(error?.message || 'Something went wrong.');
8695
setIsLoading(false);
96+
setIsDisabled?.(false);
8797

8898
return;
8999
}
@@ -106,14 +116,15 @@ export function LinkedInButton(props: LinkedInButtonProps) {
106116
.catch((err) => {
107117
setError('Something went wrong. Please try again later.');
108118
setIsLoading(false);
119+
setIsDisabled?.(false);
109120
});
110121
};
111122

112123
return (
113124
<>
114125
<button
115126
className="inline-flex h-10 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white p-2 text-sm font-medium text-black outline-none focus:ring-2 focus:ring-[#333] focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60"
116-
disabled={isLoading}
127+
disabled={isLoading || isDisabled}
117128
onClick={handleClick}
118129
>
119130
{isLoading ? (
Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,20 @@
11
---
22
import Popup from '../Popup/Popup.astro';
3-
import { EmailLoginForm } from './EmailLoginForm';
4-
import Divider from './Divider.astro';
5-
import { GitHubButton } from './GitHubButton';
6-
import { GoogleButton } from './GoogleButton';
7-
import { LinkedInButton } from './LinkedInButton';
3+
import { AuthenticationForm } from './AuthenticationForm';
84
---
95

106
<Popup id='login-popup' title='' subtitle=''>
11-
<div class='text-center'>
7+
<div class='mb-7 text-center'>
128
<p class='mb-3 text-2xl font-semibold leading-5 text-slate-900'>
139
Login to your account
1410
</p>
1511
<p class='mt-2 text-sm leading-4 text-slate-600'>
1612
You must be logged in to perform this action.
1713
</p>
1814
</div>
19-
20-
<div class='mt-7 flex flex-col gap-2'>
21-
<GitHubButton client:load />
22-
<GoogleButton client:load />
23-
<LinkedInButton client:load />
24-
</div>
25-
26-
<Divider />
27-
28-
<EmailLoginForm client:load />
29-
15+
<AuthenticationForm client:load />
3016
<div class='mt-6 text-center text-sm text-slate-600'>
3117
Don't have an account?{' '}
32-
<a href='/signup' class='font-medium text-[#4285f4]'>Sign up</a>
18+
<a href='/signup' class='font-medium text-[#4285f4]'> Sign up</a>
3319
</div>
3420
</Popup>

0 commit comments

Comments
 (0)