Skip to content

Commit 2fc3bc4

Browse files
authored
Merge pull request #980 from PayButton/button-component
chore: Add button component
2 parents 43b18fd + 1d9b132 commit 2fc3bc4

21 files changed

+268
-81
lines changed

components/Auth/ForgotPassword.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useForm } from 'react-hook-form'
22
import React, { ReactElement, useState } from 'react'
33
import style from './auth.module.css'
44
import { sendPasswordResetEmail } from 'supertokens-web-js/recipe/emailpassword'
5+
import Button from 'components/Button'
56

67
export default function SignUp (): ReactElement {
78
const { register, handleSubmit, reset } = useForm<any>()
@@ -51,7 +52,7 @@ export default function SignUp (): ReactElement {
5152
<div className={style.error_message}>
5253
{error !== '' ? <span>{error}</span> : <span></span>}
5354
</div>
54-
<button disabled={disabled} type='submit' className='button_main'>Send email</button>
55+
<Button type='submit' disabled={disabled} loading={disabled} className='lg'>Send email</Button>
5556
</div>
5657
<div>
5758
<a href="/signin" className={style.smlink}>Back</a>

components/Auth/ResetPassword.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React, { ReactElement, useEffect, useState } from 'react'
33
import style from './auth.module.css'
44
import { SignUpPasswordPOSTParameters } from 'utils/validators'
55
import { submitNewPassword } from 'supertokens-web-js/recipe/emailpassword'
6+
import Button from 'components/Button'
67

78
export default function ResetPassword (): ReactElement {
89
const { register, handleSubmit, watch } = useForm<any>()
@@ -78,7 +79,7 @@ export default function ResetPassword (): ReactElement {
7879
<div className={style.error_message}>
7980
{error !== '' ? <span>{error}</span> : <span></span>}
8081
</div>
81-
<button disabled={disabled} className='button_main' type='submit'>Submit</button>
82+
<Button type='submit' disabled={disabled} loading={disabled} className='lg'>Submit</Button>
8283
</div>
8384
</form>
8485
</>

components/Auth/SignIn.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useForm } from 'react-hook-form'
22
import React, { ReactElement, useState } from 'react'
33
import style from './auth.module.css'
44
import { signIn } from 'supertokens-web-js/recipe/emailpassword'
5+
import Button from 'components/Button'
56

67
export default function SignIn (): ReactElement {
78
const { register, handleSubmit, reset } = useForm<any>()
@@ -60,7 +61,7 @@ export default function SignIn (): ReactElement {
6061
<div className={style.error_message}>
6162
{error !== '' ? <span>{error}</span> : <span></span>}
6263
</div>
63-
<button disabled={disabled} className="button_main" type='submit'>Submit</button>
64+
<Button type='submit' disabled={disabled} loading={disabled} className='lg'>Submit</Button>
6465
</div>
6566
</form>
6667
<div className={style.signup_ctn}>

components/Auth/SignUp.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@ import React, { ReactElement, useEffect, useState } from 'react'
33
import style from './auth.module.css'
44
import { signUp } from 'supertokens-web-js/recipe/emailpassword'
55
import { SignUpPasswordPOSTParameters } from 'utils/validators'
6+
import Button from 'components/Button'
67

78
export default function SignUp (): ReactElement {
89
const { register, handleSubmit, watch, reset } = useForm<any>()
910
const [error, setError] = useState('')
11+
const [loading, setLoading] = useState(false)
1012
const [disabled, setDisabled] = useState(true)
1113
const onSubmit = async (values: any): Promise<void> => {
1214
setDisabled(true)
15+
setLoading(true)
1316

1417
const email = values.email
1518
const password = values.password
@@ -45,6 +48,7 @@ export default function SignUp (): ReactElement {
4548
}
4649
}
4750
setDisabled(false)
51+
setLoading(false)
4852
}
4953

5054
const noEmptyValues = (value: SignUpPasswordPOSTParameters): boolean => {
@@ -92,7 +96,7 @@ export default function SignUp (): ReactElement {
9296
<div className={style.error_message}>
9397
{error !== '' ? <span>{error}</span> : <span></span>}
9498
</div>
95-
<button disabled={disabled} type='submit' className='button_main'>Submit</button>
99+
<Button type='submit' disabled={disabled} loading={loading} className='lg'>Submit</Button>
96100
</div>
97101
</form>
98102
<div className={style.signup_ctn}>
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
.button {
2+
background: var(--accent-color);
3+
color: var(--primary-text-color);
4+
border-radius: 6px;
5+
padding: 8px 40px;
6+
transition: all ease-in-out 200ms;
7+
font-size: 16px;
8+
border: 1px solid var(--border-color);
9+
font-weight: 500;
10+
font-family: 'Poppins', sans-serif;
11+
position: relative;
12+
margin: 0;
13+
}
14+
15+
.button:hover {
16+
background: var(--hover-accent-color);
17+
}
18+
19+
.button:disabled {
20+
background-color: #c0c0c0;
21+
color: #5f5e5e;
22+
border-color: #c0c0c0;
23+
}
24+
25+
.button:disabled:hover {
26+
background-color: #c0c0c0;
27+
}
28+
29+
.outlined {
30+
background-color: var(--secondary-bg-color);
31+
}
32+
33+
body[data-theme='dark'] .default {
34+
color: var(--primary-bg-color);
35+
border-color: var(--primary-bg-color);
36+
}
37+
38+
.delete {
39+
background-color: var(--primary-bg-color);
40+
color: rgb(219, 37, 37);
41+
font-weight: 700;
42+
border-color: rgb(219, 37, 37);
43+
}
44+
45+
.delete:hover {
46+
background-color: rgb(219, 37, 37);
47+
color: var(--primary-text-color);
48+
}
49+
50+
.loading {
51+
color: transparent !important;
52+
}
53+
54+
.small {
55+
padding: 4px 26px;
56+
background-color: var(--secondary-bg-color);
57+
}
58+
59+
.xs {
60+
padding: 4px 10px;
61+
background-color: var(--secondary-bg-color);
62+
}
63+
64+
.ml {
65+
margin-left: 10px;
66+
}
67+
68+
.small_delete {
69+
margin-top: 10px;
70+
background-color: var(--primary-bg-color);
71+
color: rgb(219, 37, 37);
72+
font-weight: 700;
73+
border-color: rgb(219, 37, 37);
74+
}
75+
76+
.small_delete:hover {
77+
background-color: rgb(219, 37, 37);
78+
color: var(--primary-text-color);
79+
}
80+
81+
.lg {
82+
padding: 15px 40px;
83+
}
84+
85+
/**************************** Loading Spinner *************************/
86+
87+
.loading_spinner_ctn {
88+
width: 100%;
89+
height: 100%;
90+
position: absolute;
91+
top: 0;
92+
left: 0;
93+
display: flex;
94+
align-items: center;
95+
justify-content: center;
96+
border-radius: 6px;
97+
z-index: 5;
98+
}
99+
100+
.loading_spinner {
101+
display: inline-block;
102+
width: 24px;
103+
height: 24px;
104+
border: 3px solid rgba(255, 255, 255, 0.3);
105+
border-radius: 50%;
106+
border-top-color: var(--primary-text-color);
107+
animation: spin 1s ease-in-out infinite;
108+
}
109+
110+
@keyframes spin {
111+
to {
112+
transform: rotate(360deg);
113+
}
114+
}

components/Button/index.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { ReactNode, MouseEventHandler } from 'react'
2+
import style from './button.module.css'
3+
4+
const LoadingSpinner = (): JSX.Element => {
5+
return (
6+
<div className={style.loading_spinner_ctn}>
7+
<div className={style.loading_spinner} />
8+
</div>
9+
)
10+
}
11+
12+
interface ButtonProps {
13+
children: ReactNode
14+
disabled?: boolean
15+
type?: 'button' | 'submit' | 'reset'
16+
onClick?: MouseEventHandler<HTMLButtonElement>
17+
variant?: 'default' | 'outlined' | 'delete' | 'small' | 'xs'
18+
className?: string
19+
loading?: boolean
20+
}
21+
22+
export default function TopBar ({
23+
children,
24+
disabled,
25+
type = 'button',
26+
onClick,
27+
variant = 'default',
28+
className = '',
29+
loading
30+
}: ButtonProps): JSX.Element {
31+
return (
32+
<button
33+
disabled={disabled}
34+
type={type}
35+
className={`${style.button} ${style[variant]} ${style[className]} ${
36+
loading === true ? style.loading : ''
37+
}`}
38+
onClick={onClick}
39+
>
40+
{children}
41+
{loading === true && <LoadingSpinner />}
42+
</button>
43+
)
44+
}

components/Organization/CreateOrganization.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
11
import { useForm } from 'react-hook-form'
22
import { UserWithSupertokens } from 'services/userService'
33
import style from './organization.module.css'
4+
import Button from 'components/Button'
45

56
interface IProps {
67
user: UserWithSupertokens
78
setError: Function
89
setOrg: Function
910
setOrgMembers: Function
11+
setLoading: Function
12+
loading: boolean
1013
}
1114

1215
interface CreateOrganizationForm {
1316
name: string
1417
userId: string
1518
}
1619

17-
const CreateOrganization = ({ user, setError, setOrg, setOrgMembers }: IProps): JSX.Element => {
20+
const CreateOrganization = ({ user, setError, setOrg, setOrgMembers, loading, setLoading }: IProps): JSX.Element => {
1821
const { register, handleSubmit } = useForm<CreateOrganizationForm>({
1922
})
2023

2124
const onSubmit = async (params: any): Promise<void> => {
25+
setLoading(true)
2226
const res = await fetch('/api/organization', {
2327
method: 'POST',
2428
headers: {
@@ -33,9 +37,11 @@ const CreateOrganization = ({ user, setError, setOrg, setOrgMembers }: IProps):
3337
const data = await res.json()
3438
setOrg(data.organization)
3539
setOrgMembers([user.userProfile])
40+
setLoading(false)
3641
} else {
3742
const json = await res.json()
3843
setError(json.message)
44+
setLoading(false)
3945
}
4046
}
4147

@@ -53,9 +59,7 @@ const CreateOrganization = ({ user, setError, setOrg, setOrgMembers }: IProps):
5359
required
5460
className={style.text_input}
5561
/>
56-
<button className={style.add_btn} onClick={() => (false)}>
57-
Create
58-
</button>
62+
<Button className='ml' type='submit' loading={loading}>Create</Button>
5963
</div>
6064
</form>
6165
}

components/Organization/DeleteOrganization.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Organization } from '@prisma/client'
22
import { UserWithSupertokens } from 'services/userService'
33
import style from './organization.module.css'
4+
import Button from 'components/Button'
45

56
interface IProps {
67
user: UserWithSupertokens
@@ -30,14 +31,14 @@ const DeleteOrganization = ({ user, setError, setOrg, org, setOrgEdit }: IProps)
3031

3132
return (<>
3233
<div className={style.confirm_delete_ctn}>
33-
<p>Are you sure you want to delete your organization?<br />This action cannot be undone.</p>
34+
<p>Are you sure you want to delete your organization? This action cannot be undone.</p>
3435
<div className={style.confirm_delete_btn_ctn}>
35-
<button className={style.delete_btn} onClick={() => { void onDelete() }}>
36-
Yes, Delete Organization
37-
</button>
38-
<button className={style.cancel_btn} onClick={() => setOrgEdit('')}>
36+
<Button variant='xs' onClick={() => setOrgEdit('')}>
3937
Cancel
40-
</button>
38+
</Button>
39+
<Button variant='xs' onClick={() => { void onDelete() }} className='small_delete'>
40+
Yes, Delete Organization
41+
</Button>
4142
</div>
4243
</div>
4344
</>

components/Organization/LeaveOrganization.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Organization } from '@prisma/client'
22
import { UserWithSupertokens } from 'services/userService'
33
import style from './organization.module.css'
4+
import Button from 'components/Button'
45

56
interface IProps {
67
user: UserWithSupertokens
@@ -32,12 +33,12 @@ const LeaveOrganization = ({ setError, setOrg, org, setOrgEdit }: IProps): JSX.E
3233
<div className={style.confirm_delete_ctn} style={{ marginTop: '40px' }}>
3334
<p>Are you sure you want to leave your organization?<br />This action cannot be undone.</p>
3435
<div className={style.confirm_delete_btn_ctn}>
35-
<button className={style.delete_btn} onClick={() => { void onLeave() }}>
36-
Yes, Leave Organization
37-
</button>
38-
<button className={style.cancel_btn} onClick={() => setOrgEdit('')}>
36+
<Button variant='xs' onClick={() => setOrgEdit('')}>
3937
Cancel
40-
</button>
38+
</Button>
39+
<Button variant='xs' className='small_delete' onClick={() => { void onLeave() }}>
40+
Yes, Leave Organization
41+
</Button>
4142
</div>
4243
</div>
4344
</>

components/Organization/UpdateOrganization.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useForm } from 'react-hook-form'
22
import { UserWithSupertokens } from 'services/userService'
33
import style from './organization.module.css'
4+
import Button from 'components/Button'
45

56
interface IProps {
67
user: UserWithSupertokens
@@ -54,9 +55,9 @@ const UpdateOrganization = ({ user, setError, setOrg, setOrgEdit }: IProps): JSX
5455
required
5556
className={style.text_input}
5657
/>
57-
<button className={style.add_btn} onClick={() => (false)}>
58+
<Button className='ml' type='submit'>
5859
Update
59-
</button>
60+
</Button>
6061
</div>
6162
<button className={style.cancel_btn} onClick={() => setOrgEdit('')}>
6263
Cancel

0 commit comments

Comments
 (0)