-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
353 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export { default as LoginPanel } from './login-panel' | ||
export { default as EmailPasswordForm } from './email-password-form' | ||
export { default as AuthWidget } from './auth-widget' | ||
export { default as AuthWidget } from './auth-widget' | ||
export { default as SignupPanel } from './signup-panel' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
'use client' | ||
import { useState, type PropsWithChildren } from 'react' | ||
import { useRouter } from 'next/navigation' | ||
import { observer } from 'mobx-react-lite' | ||
import Link from 'next/link' | ||
|
||
import { ApplyTypography, Button, Separator, toast, Toaster } from '@hanzo/ui/primitives' | ||
import { cn } from '@hanzo/ui/util' | ||
|
||
import { useAuth, type AuthProvider } from '../service' | ||
import { Facebook, Google, GitHub } from '../icons' | ||
import EmailPasswordForm from './email-password-form' | ||
import { sendGAEvent } from '../util/analytics' | ||
|
||
|
||
const ProviderLoginButton: React.FC<PropsWithChildren & { | ||
provider: AuthProvider, | ||
loginWithProvider: (provider: AuthProvider) => Promise<void>, | ||
isLoading: boolean | ||
}> = ({ | ||
provider, | ||
loginWithProvider, | ||
isLoading, | ||
children | ||
}) => { | ||
|
||
return ( | ||
<Button | ||
onClick={() => loginWithProvider(provider)} | ||
className='w-full mx-auto flex items-center gap-2' | ||
disabled={isLoading} | ||
variant='outline' | ||
> | ||
{children} | ||
</Button> | ||
) | ||
} | ||
|
||
const SignupPanel: React.FC<PropsWithChildren & { | ||
redirectUrl?: string, | ||
getStartedUrl?: string, | ||
className?: string, | ||
inputClx?: string, | ||
noHeading?: boolean | ||
onLoginChanged?: (token: string) => void | ||
termsOfServiceUrl?: string | ||
privacyPolicyUrl?: string | ||
setIsLogin?: React.Dispatch<React.SetStateAction<boolean>> | ||
}> = observer(({ | ||
children, | ||
redirectUrl, | ||
getStartedUrl, | ||
className, | ||
inputClx, | ||
noHeading, | ||
onLoginChanged, | ||
termsOfServiceUrl, | ||
privacyPolicyUrl, | ||
setIsLogin | ||
}) => { | ||
|
||
const router = useRouter() | ||
const auth = useAuth() | ||
const [isLoading, setIsLoading] = useState(false) | ||
|
||
const succeed = async (loginMethod: AuthProvider | 'email' | null) => { | ||
|
||
if (loginMethod) { | ||
sendGAEvent('login', { method: loginMethod }) | ||
} | ||
|
||
// If a callback is provided, don't redirect. | ||
// Assume host code is handling (eg, mobile menu) | ||
if (onLoginChanged) { | ||
const res = await fetch( | ||
'/api/auth/generate-custom-token', | ||
{ method: 'POST' } | ||
).then(res => res.json()) | ||
onLoginChanged(res.token?.token ?? null) | ||
} | ||
else if (redirectUrl) { | ||
// TODO :aa shouldn't the token thing happen in this case too?? | ||
router.push(redirectUrl) | ||
} | ||
} | ||
|
||
const signupWithEmailPassword = async (email: string, password: string) => { | ||
setIsLoading(true) | ||
try { | ||
const res = await auth.signupEmailAndPassword(email, password) | ||
if (res.success) { succeed('email'); toast.success(res.message) } | ||
else { toast.error(res.message) } | ||
} | ||
catch (e) { | ||
toast.success('User with this email already signed up') | ||
} | ||
setIsLoading(false) | ||
} | ||
|
||
// const loginWithEthereum = async () => { | ||
// setIsLoading(true) | ||
// try { | ||
// const res = await signInWithEthereum() | ||
// if (res.success && res.user) { | ||
// setUser({email: res.user?.email, displayName: res.user?.displayName, walletAddress: res.user?.walletAddress}) | ||
// if (redirectUrl) { | ||
// router.push(redirectUrl) | ||
// } | ||
// } | ||
// } catch (e) { | ||
// toast({title: 'No Ethereum provider found'}) | ||
// } | ||
// setIsLoading(false) | ||
// } | ||
|
||
const loginWithProvider = async (provider: AuthProvider) => { | ||
setIsLoading(true) | ||
const res = await auth.loginWithProvider(provider) | ||
if (res.success) { succeed(provider) } | ||
setIsLoading(false) | ||
} | ||
|
||
const logout = async () => { | ||
setIsLoading(true) | ||
const res = await auth.logout() | ||
if (res.success) { succeed(null) } | ||
setIsLoading(false) | ||
} | ||
|
||
const handleOnClick = () => { | ||
if (setIsLogin) setIsLogin(true) | ||
} | ||
|
||
return ( | ||
<ApplyTypography className={cn('w-full flex flex-col text-center !gap-3 LOGIN_OUTER', className)}> | ||
{auth.loggedIn && !redirectUrl ? ( | ||
<> | ||
<h4>Welcome!</h4> | ||
{auth.user && (<> {/* this means the hanzo user isn't loaded yet ...*/} | ||
<p>You are signed in as {auth.user?.displayName ?? auth.user?.email}</p> | ||
<div className='flex flex-col md:flex-row gap-3 items-center justify-center'> | ||
{getStartedUrl && <Button variant='primary' onClick={() => router.push(getStartedUrl)} className='w-full'>GET STARTED</Button>} | ||
<Button onClick={() => logout()} variant='outline' disabled={isLoading} className='w-full'>Sign Out</Button> | ||
</div> | ||
</>)} | ||
</> | ||
) : ( | ||
<> | ||
{!noHeading && ( | ||
<h4 className='text-center'>SignUp</h4> | ||
)} | ||
{children} | ||
<EmailPasswordForm onSubmit={signupWithEmailPassword} isLoading={isLoading} className='mb-4' inputClx={inputClx} content='SignUp' /> | ||
|
||
<div className='flex flex-row gap-4 justify-center'> | ||
<div className='text-muted-2 text-sm'>Already have account?</div> | ||
<button className='bg-transparent text-foreground text-sm' onClick={handleOnClick}>Log In</button> | ||
</div> | ||
|
||
<div className='flex gap-2 whitespace-nowrap items-center my-1 sm:my-3 text-xs text-muted'> | ||
<Separator className='grow w-auto' /><div className='shrink-0 mx-1'>or continue with</div><Separator className='grow w-auto' /> | ||
</div> | ||
|
||
{/* <Button onClick={loginWithEthereum} className='w-full mx-auto flex items-center gap-2' disabled={isLoading}> | ||
<Ethereum height={20}/>Login with your wallet | ||
</Button> */} | ||
<ProviderLoginButton provider='google' isLoading={isLoading} loginWithProvider={loginWithProvider}> | ||
<Google height={20} />Google | ||
</ProviderLoginButton> | ||
<ProviderLoginButton provider='facebook' isLoading={isLoading} loginWithProvider={loginWithProvider}> | ||
<Facebook height={20} />Facebook | ||
</ProviderLoginButton> | ||
<ProviderLoginButton provider='github' isLoading={isLoading} loginWithProvider={loginWithProvider}> | ||
<GitHub height={20} />Github | ||
</ProviderLoginButton> | ||
<p className='text-sm text-muted-2'>By logging in, you agree to our <Link href={termsOfServiceUrl ?? ''} target='_blank'>Terms of Service</Link> and <Link href={privacyPolicyUrl ?? ''} target='_blank'>Privacy Policy</Link>.</p> | ||
<Toaster></Toaster> | ||
</> | ||
)} | ||
</ApplyTypography> | ||
) | ||
}) | ||
|
||
export default SignupPanel |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.