diff --git a/components/Auth/ForgotPassword.tsx b/components/Auth/ForgotPassword.tsx index f8207c5c0..08251304c 100644 --- a/components/Auth/ForgotPassword.tsx +++ b/components/Auth/ForgotPassword.tsx @@ -2,6 +2,7 @@ import { useForm } from 'react-hook-form' import React, { ReactElement, useState } from 'react' import style from './auth.module.css' import { sendPasswordResetEmail } from 'supertokens-web-js/recipe/emailpassword' +import Button from 'components/Button' export default function SignUp (): ReactElement { const { register, handleSubmit, reset } = useForm() @@ -51,7 +52,7 @@ export default function SignUp (): ReactElement {
{error !== '' ? {error} : }
- +
Back diff --git a/components/Auth/ResetPassword.tsx b/components/Auth/ResetPassword.tsx index 519087859..963743736 100644 --- a/components/Auth/ResetPassword.tsx +++ b/components/Auth/ResetPassword.tsx @@ -3,6 +3,7 @@ import React, { ReactElement, useEffect, useState } from 'react' import style from './auth.module.css' import { SignUpPasswordPOSTParameters } from 'utils/validators' import { submitNewPassword } from 'supertokens-web-js/recipe/emailpassword' +import Button from 'components/Button' export default function ResetPassword (): ReactElement { const { register, handleSubmit, watch } = useForm() @@ -78,7 +79,7 @@ export default function ResetPassword (): ReactElement {
{error !== '' ? {error} : }
- +
diff --git a/components/Auth/SignIn.tsx b/components/Auth/SignIn.tsx index a9e554f99..ddf985c26 100644 --- a/components/Auth/SignIn.tsx +++ b/components/Auth/SignIn.tsx @@ -2,6 +2,7 @@ import { useForm } from 'react-hook-form' import React, { ReactElement, useState } from 'react' import style from './auth.module.css' import { signIn } from 'supertokens-web-js/recipe/emailpassword' +import Button from 'components/Button' export default function SignIn (): ReactElement { const { register, handleSubmit, reset } = useForm() @@ -60,7 +61,7 @@ export default function SignIn (): ReactElement {
{error !== '' ? {error} : }
- +
diff --git a/components/Auth/SignUp.tsx b/components/Auth/SignUp.tsx index 2b716015e..2675e77b7 100644 --- a/components/Auth/SignUp.tsx +++ b/components/Auth/SignUp.tsx @@ -3,13 +3,16 @@ import React, { ReactElement, useEffect, useState } from 'react' import style from './auth.module.css' import { signUp } from 'supertokens-web-js/recipe/emailpassword' import { SignUpPasswordPOSTParameters } from 'utils/validators' +import Button from 'components/Button' export default function SignUp (): ReactElement { const { register, handleSubmit, watch, reset } = useForm() const [error, setError] = useState('') + const [loading, setLoading] = useState(false) const [disabled, setDisabled] = useState(true) const onSubmit = async (values: any): Promise => { setDisabled(true) + setLoading(true) const email = values.email const password = values.password @@ -45,6 +48,7 @@ export default function SignUp (): ReactElement { } } setDisabled(false) + setLoading(false) } const noEmptyValues = (value: SignUpPasswordPOSTParameters): boolean => { @@ -92,7 +96,7 @@ export default function SignUp (): ReactElement {
{error !== '' ? {error} : }
- +
diff --git a/components/Button/button.module.css b/components/Button/button.module.css new file mode 100644 index 000000000..b5925aa15 --- /dev/null +++ b/components/Button/button.module.css @@ -0,0 +1,114 @@ +.button { + background: var(--accent-color); + color: var(--primary-text-color); + border-radius: 6px; + padding: 8px 40px; + transition: all ease-in-out 200ms; + font-size: 16px; + border: 1px solid var(--border-color); + font-weight: 500; + font-family: 'Poppins', sans-serif; + position: relative; + margin: 0; +} + +.button:hover { + background: var(--hover-accent-color); +} + +.button:disabled { + background-color: #c0c0c0; + color: #5f5e5e; + border-color: #c0c0c0; +} + +.button:disabled:hover { + background-color: #c0c0c0; +} + +.outlined { + background-color: var(--secondary-bg-color); +} + +body[data-theme='dark'] .default { + color: var(--primary-bg-color); + border-color: var(--primary-bg-color); +} + +.delete { + background-color: var(--primary-bg-color); + color: rgb(219, 37, 37); + font-weight: 700; + border-color: rgb(219, 37, 37); +} + +.delete:hover { + background-color: rgb(219, 37, 37); + color: var(--primary-text-color); +} + +.loading { + color: transparent !important; +} + +.small { + padding: 4px 26px; + background-color: var(--secondary-bg-color); +} + +.xs { + padding: 4px 10px; + background-color: var(--secondary-bg-color); +} + +.ml { + margin-left: 10px; +} + +.small_delete { + margin-top: 10px; + background-color: var(--primary-bg-color); + color: rgb(219, 37, 37); + font-weight: 700; + border-color: rgb(219, 37, 37); +} + +.small_delete:hover { + background-color: rgb(219, 37, 37); + color: var(--primary-text-color); +} + +.lg { + padding: 15px 40px; +} + +/**************************** Loading Spinner *************************/ + +.loading_spinner_ctn { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + display: flex; + align-items: center; + justify-content: center; + border-radius: 6px; + z-index: 5; +} + +.loading_spinner { + display: inline-block; + width: 24px; + height: 24px; + border: 3px solid rgba(255, 255, 255, 0.3); + border-radius: 50%; + border-top-color: var(--primary-text-color); + animation: spin 1s ease-in-out infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} diff --git a/components/Button/index.tsx b/components/Button/index.tsx new file mode 100644 index 000000000..367d981a8 --- /dev/null +++ b/components/Button/index.tsx @@ -0,0 +1,44 @@ +import { ReactNode, MouseEventHandler } from 'react' +import style from './button.module.css' + +const LoadingSpinner = (): JSX.Element => { + return ( +
+
+
+ ) +} + +interface ButtonProps { + children: ReactNode + disabled?: boolean + type?: 'button' | 'submit' | 'reset' + onClick?: MouseEventHandler + variant?: 'default' | 'outlined' | 'delete' | 'small' | 'xs' + className?: string + loading?: boolean +} + +export default function TopBar ({ + children, + disabled, + type = 'button', + onClick, + variant = 'default', + className = '', + loading +}: ButtonProps): JSX.Element { + return ( + + ) +} diff --git a/components/Organization/CreateOrganization.tsx b/components/Organization/CreateOrganization.tsx index ca5642b6f..a7ab7457e 100644 --- a/components/Organization/CreateOrganization.tsx +++ b/components/Organization/CreateOrganization.tsx @@ -1,12 +1,15 @@ import { useForm } from 'react-hook-form' import { UserWithSupertokens } from 'services/userService' import style from './organization.module.css' +import Button from 'components/Button' interface IProps { user: UserWithSupertokens setError: Function setOrg: Function setOrgMembers: Function + setLoading: Function + loading: boolean } interface CreateOrganizationForm { @@ -14,11 +17,12 @@ interface CreateOrganizationForm { userId: string } -const CreateOrganization = ({ user, setError, setOrg, setOrgMembers }: IProps): JSX.Element => { +const CreateOrganization = ({ user, setError, setOrg, setOrgMembers, loading, setLoading }: IProps): JSX.Element => { const { register, handleSubmit } = useForm({ }) const onSubmit = async (params: any): Promise => { + setLoading(true) const res = await fetch('/api/organization', { method: 'POST', headers: { @@ -33,9 +37,11 @@ const CreateOrganization = ({ user, setError, setOrg, setOrgMembers }: IProps): const data = await res.json() setOrg(data.organization) setOrgMembers([user.userProfile]) + setLoading(false) } else { const json = await res.json() setError(json.message) + setLoading(false) } } @@ -53,9 +59,7 @@ const CreateOrganization = ({ user, setError, setOrg, setOrgMembers }: IProps): required className={style.text_input} /> - +
} diff --git a/components/Organization/DeleteOrganization.tsx b/components/Organization/DeleteOrganization.tsx index 718189a1c..2d56479bd 100644 --- a/components/Organization/DeleteOrganization.tsx +++ b/components/Organization/DeleteOrganization.tsx @@ -1,6 +1,7 @@ import { Organization } from '@prisma/client' import { UserWithSupertokens } from 'services/userService' import style from './organization.module.css' +import Button from 'components/Button' interface IProps { user: UserWithSupertokens @@ -30,14 +31,14 @@ const DeleteOrganization = ({ user, setError, setOrg, org, setOrgEdit }: IProps) return (<>
-

Are you sure you want to delete your organization?
This action cannot be undone.

+

Are you sure you want to delete your organization? This action cannot be undone.

- - + +
diff --git a/components/Organization/LeaveOrganization.tsx b/components/Organization/LeaveOrganization.tsx index 1fd44421d..681fc0da3 100644 --- a/components/Organization/LeaveOrganization.tsx +++ b/components/Organization/LeaveOrganization.tsx @@ -1,6 +1,7 @@ import { Organization } from '@prisma/client' import { UserWithSupertokens } from 'services/userService' import style from './organization.module.css' +import Button from 'components/Button' interface IProps { user: UserWithSupertokens @@ -32,12 +33,12 @@ const LeaveOrganization = ({ setError, setOrg, org, setOrgEdit }: IProps): JSX.E

Are you sure you want to leave your organization?
This action cannot be undone.

- - + +
diff --git a/components/Organization/UpdateOrganization.tsx b/components/Organization/UpdateOrganization.tsx index ac76d7b15..4d752886e 100644 --- a/components/Organization/UpdateOrganization.tsx +++ b/components/Organization/UpdateOrganization.tsx @@ -1,6 +1,7 @@ import { useForm } from 'react-hook-form' import { UserWithSupertokens } from 'services/userService' import style from './organization.module.css' +import Button from 'components/Button' interface IProps { user: UserWithSupertokens @@ -54,9 +55,9 @@ const UpdateOrganization = ({ user, setError, setOrg, setOrgEdit }: IProps): JSX required className={style.text_input} /> - +
Delete Organization
-
setOrgEdit('delete')} > Delete Organization -
+
) @@ -102,12 +105,11 @@ const ViewOrganization = ({ user, orgMembers, setOrgMembers, organization }: IPr {orgEdit === '' ? (
-
setOrgEdit('leave')} > Leave Organization -
+
) : ( @@ -122,7 +124,7 @@ const ViewOrganization = ({ user, orgMembers, setOrgMembers, organization }: IPr
Or create your own:

- + )} {error !== '' &&
{error}
} diff --git a/components/Organization/organization.module.css b/components/Organization/organization.module.css index 49f4ab832..18fe336cd 100644 --- a/components/Organization/organization.module.css +++ b/components/Organization/organization.module.css @@ -29,12 +29,6 @@ body[data-theme="dark"] .org_ctn input { margin: 0; } -.create_input_ctn button { - width: 120px; - margin: 0; - margin-left: 10px; -} - .error_message { width: 100%; background-color: rgb(250, 165, 165); @@ -47,6 +41,7 @@ body[data-theme="dark"] .org_ctn input { display: flex; margin-top: 10px; justify-content: space-between; + align-items: center; } .sub_header { @@ -134,10 +129,7 @@ body[data-theme="dark"] .cancel_btn:hover { .confirm_delete_btn_ctn { display: flex; flex-direction: column; -} - -.confirm_delete_btn_ctn button { - height: 30px; + margin-left: 10px; } .leave_btn_ctn { diff --git a/components/Paybutton/EditButtonForm.tsx b/components/Paybutton/EditButtonForm.tsx index 11bbbacd4..5590f434b 100644 --- a/components/Paybutton/EditButtonForm.tsx +++ b/components/Paybutton/EditButtonForm.tsx @@ -10,6 +10,7 @@ import TrashIcon from 'assets/trash-icon.png' import axios from 'axios' import Router from 'next/router' import config from 'config' +import Button from 'components/Button' interface IProps { paybutton: PaybuttonWithAddresses @@ -92,8 +93,8 @@ export default function EditButtonForm ({ paybutton, refreshPaybutton }: IProps) {(error === undefined || error === '') ? null :
{error}
}
- - + +
@@ -112,9 +113,8 @@ export default function EditButtonForm ({ paybutton, refreshPaybutton }: IProps)
{(deleteError === undefined || deleteError === '') ? null :
{deleteError}
}
- - - + +
diff --git a/components/Paybutton/PaybuttonForm.tsx b/components/Paybutton/PaybuttonForm.tsx index f4b3d9ce7..2b177538b 100644 --- a/components/Paybutton/PaybuttonForm.tsx +++ b/components/Paybutton/PaybuttonForm.tsx @@ -5,7 +5,7 @@ import { WalletWithAddressesWithPaybuttons } from 'services/walletService' import Image from 'next/image' import style from './paybutton.module.css' import Plus from 'assets/plus.png' -import LoadingSpinner from './LoadingSpinner' +import Button from 'components/Button' interface IProps { onSubmit: (data: PaybuttonPOSTParameters) => Promise @@ -87,8 +87,8 @@ export default function PaybuttonForm ({ onSubmit, paybuttons, wallets, error }: