mirror of
https://github.com/penxio/penx.git
synced 2026-05-12 03:03:12 -04:00
feat: improve email login
This commit is contained in:
@@ -46,6 +46,7 @@ import { useEffect, useRef } from 'react'
|
||||
import { appEmitter } from '@penx/emitter'
|
||||
import { useCreationId } from '@penx/hooks/useCreationId'
|
||||
import { ICreationNode } from '@penx/model-type'
|
||||
import { NavProvider } from './components/NavContext'
|
||||
import { PageCreation } from './pages/PageCreation'
|
||||
|
||||
async function init() {
|
||||
@@ -120,7 +121,6 @@ setupIonicReact()
|
||||
|
||||
const App: React.FC = () => {
|
||||
const nav = useRef<HTMLIonNavElement>(null)
|
||||
const { creationId, setCreationId } = useCreationId()
|
||||
|
||||
useEffect(() => {
|
||||
// if (initRef.current) return
|
||||
@@ -153,7 +153,9 @@ const App: React.FC = () => {
|
||||
<Redirect to="/folder/area" />
|
||||
</Route>
|
||||
<Route path="/folder/:name" exact={true}>
|
||||
<IonNav ref={nav} root={() => <PageHome />}></IonNav>
|
||||
<NavProvider nav={nav.current!}>
|
||||
<IonNav ref={nav} root={() => <PageHome />}></IonNav>
|
||||
</NavProvider>
|
||||
</Route>
|
||||
</IonRouterOutlet>
|
||||
</IonSplitPane>
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { PageEmailLogin } from '@/pages/PageEmailLogin'
|
||||
import { Capacitor } from '@capacitor/core'
|
||||
import { SocialLogin } from '@capgo/capacitor-social-login'
|
||||
import { IonButton, IonNavLink, useIonRouter } from '@ionic/react'
|
||||
import { set } from 'idb-keyval'
|
||||
import { MailIcon } from 'lucide-react'
|
||||
import { appEmitter } from '@penx/emitter'
|
||||
import { localDB } from '@penx/local-db'
|
||||
import { queryClient } from '@penx/query-client'
|
||||
import { useSession } from '@penx/session'
|
||||
import { MobileGoogleLoginInfo } from '@penx/types'
|
||||
import { Button } from '@penx/uikit/button'
|
||||
import { IconGoogle } from '@penx/uikit/IconGoogle'
|
||||
import { LoadingDots } from '@penx/uikit/loading-dots'
|
||||
import { LoginForm } from './LoginForm'
|
||||
|
||||
interface Props {}
|
||||
export function EmailLoginButton({}: Props) {
|
||||
const { login } = useSession()
|
||||
const [json, setJson] = useState({})
|
||||
const [error, setError] = useState({})
|
||||
const [session, setSession] = useState({})
|
||||
const [loading, setLoading] = useState(false)
|
||||
const router = useIonRouter()
|
||||
|
||||
return (
|
||||
<IonNavLink routerDirection="forward" component={() => <PageEmailLogin />}>
|
||||
<Button className="w-full gap-2">
|
||||
{loading && <LoadingDots className="bg-foreground" />}
|
||||
{!loading && (
|
||||
<>
|
||||
<MailIcon size={20} />
|
||||
<div className="">Email login</div>
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</IonNavLink>
|
||||
)
|
||||
}
|
||||
18
apps/mobile/src/components/NavContext.tsx
Normal file
18
apps/mobile/src/components/NavContext.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
'use client'
|
||||
|
||||
import { createContext, PropsWithChildren, useContext } from 'react'
|
||||
|
||||
export const NavContext = createContext({} as HTMLIonNavElement)
|
||||
|
||||
interface Props {
|
||||
nav: HTMLIonNavElement
|
||||
}
|
||||
|
||||
export const NavProvider = ({ nav, children }: PropsWithChildren<Props>) => {
|
||||
return <NavContext.Provider value={nav}>{children}</NavContext.Provider>
|
||||
}
|
||||
|
||||
export function useNavContext() {
|
||||
const nav = useContext(NavContext)
|
||||
return nav
|
||||
}
|
||||
19
apps/mobile/src/components/Profile/EmailLoginButton.tsx
Normal file
19
apps/mobile/src/components/Profile/EmailLoginButton.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
import { PageEmailLogin } from '@/pages/PageEmailLogin'
|
||||
import { IonNavLink } from '@ionic/react'
|
||||
import { MailIcon } from 'lucide-react'
|
||||
import { Button } from '@penx/uikit/button'
|
||||
|
||||
interface Props {}
|
||||
export function EmailLoginButton({}: Props) {
|
||||
return (
|
||||
<IonNavLink routerDirection="forward" component={() => <PageEmailLogin />}>
|
||||
<Button className="w-full gap-2">
|
||||
<MailIcon size={20} />
|
||||
<div className="">Email login</div>
|
||||
</Button>
|
||||
</IonNavLink>
|
||||
)
|
||||
}
|
||||
@@ -24,7 +24,10 @@ const platform = Capacitor.getPlatform()
|
||||
export function LoginContent({}: Props) {
|
||||
return (
|
||||
<div className="flex h-full flex-1 flex-col justify-center px-6">
|
||||
<div className="space-y-2">
|
||||
<div className="-mt-20 space-y-2">
|
||||
<div className="mb-10 text-center text-2xl font-bold">
|
||||
Welcome to PenX
|
||||
</div>
|
||||
<GoogleLoginButton />
|
||||
{platform === 'ios' && <AppleLoginButton />}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { set } from 'idb-keyval'
|
||||
import { toast } from 'sonner'
|
||||
import { z } from 'zod'
|
||||
import { appEmitter } from '@penx/emitter'
|
||||
import { useRouter } from '@penx/libs/i18n'
|
||||
import { useAuthStatus } from '@penx/hooks/useAuthStatus'
|
||||
import { queryClient } from '@penx/query-client'
|
||||
import { useSession } from '@penx/session'
|
||||
import { Button } from '@penx/uikit/button'
|
||||
@@ -22,11 +22,10 @@ import {
|
||||
import { Input } from '@penx/uikit/input'
|
||||
import { LoadingDots } from '@penx/uikit/loading-dots'
|
||||
import { extractErrorMessage } from '@penx/utils/extractErrorMessage'
|
||||
import { useNavContext } from '../NavContext'
|
||||
|
||||
const FormSchema = z.object({
|
||||
name: z.string().min(4, {
|
||||
message: 'Username must be at least 4 characters.',
|
||||
}),
|
||||
name: z.string().email(),
|
||||
password: z.string().min(4, {
|
||||
message: 'Password must be at least 4 characters.',
|
||||
}),
|
||||
@@ -37,6 +36,8 @@ interface Props {}
|
||||
export function LoginForm({}: Props) {
|
||||
const [isLoading, setLoading] = useState(false)
|
||||
const { login } = useSession()
|
||||
const { setAuthStatus } = useAuthStatus()
|
||||
const nav = useNavContext()
|
||||
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
@@ -47,9 +48,9 @@ export function LoginForm({}: Props) {
|
||||
})
|
||||
|
||||
async function onSubmit(data: z.infer<typeof FormSchema>) {
|
||||
console.log('=====>>>>>>>nav:', nav);
|
||||
|
||||
try {
|
||||
console.log('======data:', data)
|
||||
|
||||
setLoading(true)
|
||||
|
||||
const session = await login({
|
||||
@@ -65,6 +66,7 @@ export function LoginForm({}: Props) {
|
||||
await set('SESSION', session)
|
||||
queryClient.setQueryData(['SESSION'], session)
|
||||
appEmitter.emit('APP_LOGIN_SUCCESS', session)
|
||||
nav.pop()
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('========error:', error)
|
||||
@@ -102,6 +104,7 @@ export function LoginForm({}: Props) {
|
||||
<FormItem className="w-full">
|
||||
<FormControl>
|
||||
<Input
|
||||
autoComplete="current-password"
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
{...field}
|
||||
@@ -124,6 +127,16 @@ export function LoginForm({}: Props) {
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div className="pt-4 text-center text-sm">
|
||||
<Trans id="No account"></Trans>?{' '}
|
||||
<span
|
||||
className="text-brand"
|
||||
onClick={() => setAuthStatus({ type: 'register' })}
|
||||
>
|
||||
<Trans id="Create one"></Trans>
|
||||
</span>
|
||||
</div>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
133
apps/mobile/src/components/Profile/PinCodeForm.tsx
Normal file
133
apps/mobile/src/components/Profile/PinCodeForm.tsx
Normal file
@@ -0,0 +1,133 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { Trans } from '@lingui/react'
|
||||
import { set } from 'idb-keyval'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import { toast } from 'sonner'
|
||||
import { z } from 'zod'
|
||||
import { appEmitter } from '@penx/emitter'
|
||||
import { useAuthStatus } from '@penx/hooks/useAuthStatus'
|
||||
import { localDB } from '@penx/local-db'
|
||||
import { queryClient } from '@penx/query-client'
|
||||
import { useSession } from '@penx/session'
|
||||
import { api } from '@penx/trpc-client'
|
||||
import { Button } from '@penx/uikit/button'
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@penx/uikit/form'
|
||||
import { Input } from '@penx/uikit/input'
|
||||
import { LoadingDots } from '@penx/uikit/loading-dots'
|
||||
import { extractErrorMessage } from '@penx/utils/extractErrorMessage'
|
||||
import { useNavContext } from '../NavContext'
|
||||
|
||||
const FormSchema = z.object({
|
||||
code: z.string(),
|
||||
})
|
||||
|
||||
interface Props {}
|
||||
|
||||
export function PinCodeForm({}: Props) {
|
||||
const { login } = useSession()
|
||||
const [isLoading, setLoading] = useState(false)
|
||||
const { authStatus } = useAuthStatus()
|
||||
const nav = useNavContext()
|
||||
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
code: '',
|
||||
},
|
||||
})
|
||||
|
||||
async function onSubmit(data: z.infer<typeof FormSchema>) {
|
||||
try {
|
||||
setLoading(true)
|
||||
const session = await login({
|
||||
type: 'register-by-code',
|
||||
code: data.code,
|
||||
})
|
||||
console.log('=====session:', session)
|
||||
|
||||
if (!session.isLoggedIn) {
|
||||
toast.error(session.message)
|
||||
} else {
|
||||
await set('SESSION', session)
|
||||
queryClient.setQueryData(['SESSION'], session)
|
||||
appEmitter.emit('APP_LOGIN_SUCCESS', session)
|
||||
nav.pop()
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('========error:', error)
|
||||
const msg = extractErrorMessage(error)
|
||||
toast.error(msg)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||
<p className="text-foreground/60">
|
||||
<Trans id="Please check your email for the verification code."></Trans>
|
||||
</p>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="code"
|
||||
render={({ field }) => (
|
||||
<FormItem className="w-full">
|
||||
<FormLabel className="flex items-center justify-between">
|
||||
<span>
|
||||
<Trans id="Login code"></Trans>
|
||||
</span>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="xs"
|
||||
onClick={async () => {
|
||||
try {
|
||||
await api.auth.registerByEmail.mutate(
|
||||
authStatus.data as any,
|
||||
)
|
||||
toast.success('Verification code sent successfully')
|
||||
} catch (error) {
|
||||
console.log('========error:', error)
|
||||
const msg = extractErrorMessage(error)
|
||||
toast.error(msg)
|
||||
}
|
||||
}}
|
||||
>
|
||||
Resend
|
||||
</Button>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="" {...field} className="w-full" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div>
|
||||
<Button
|
||||
size="lg"
|
||||
type="submit"
|
||||
className="w-full"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? <LoadingDots /> : <Trans id="Register"></Trans>}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
48
apps/mobile/src/components/Profile/ProfileContent.tsx
Normal file
48
apps/mobile/src/components/Profile/ProfileContent.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
'use client'
|
||||
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { Capacitor } from '@capacitor/core'
|
||||
import { SocialLogin } from '@capgo/capacitor-social-login'
|
||||
import { LogOutIcon } from 'lucide-react'
|
||||
import { useSession } from '@penx/session'
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@penx/uikit/avatar'
|
||||
import { cn, getUrl } from '@penx/utils'
|
||||
import { generateGradient } from '@penx/utils/generateGradient'
|
||||
|
||||
interface Props {}
|
||||
|
||||
const platform = Capacitor.getPlatform()
|
||||
|
||||
export function ProfileContent({}: Props) {
|
||||
const { session, logout } = useSession()
|
||||
return (
|
||||
<div className="flex h-full flex-1 flex-col gap-2 px-3 pt-4">
|
||||
<div className="flex items-center gap-2 py-1.5 text-left text-sm">
|
||||
<Avatar className="h-8 w-8 rounded-lg">
|
||||
<AvatarImage src={getUrl(session?.image)} alt={session?.name} />
|
||||
<AvatarFallback
|
||||
className={cn(
|
||||
'rounded-lg text-white',
|
||||
generateGradient(session.name),
|
||||
)}
|
||||
>
|
||||
{session?.name.slice(0, 1)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="grid flex-1 text-left text-sm leading-tight">
|
||||
<span className="truncate font-medium">{session?.name}</span>
|
||||
<span className="truncate text-xs">{session?.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="bg-foreground/5 flex items-center justify-between rounded-lg px-3 py-2"
|
||||
onClick={() => {
|
||||
logout()
|
||||
}}
|
||||
>
|
||||
<div>Logout</div>
|
||||
<LogOutIcon size={20} className="text-foreground/60"></LogOutIcon>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
144
apps/mobile/src/components/Profile/RegisterForm.tsx
Normal file
144
apps/mobile/src/components/Profile/RegisterForm.tsx
Normal file
@@ -0,0 +1,144 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { Trans } from '@lingui/react'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import { toast } from 'sonner'
|
||||
import { z } from 'zod'
|
||||
import { useAuthStatus } from '@penx/hooks/useAuthStatus'
|
||||
import { localDB } from '@penx/local-db'
|
||||
import { api } from '@penx/trpc-client'
|
||||
import { Button } from '@penx/uikit/button'
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@penx/uikit/form'
|
||||
import { Input } from '@penx/uikit/input'
|
||||
import { LoadingDots } from '@penx/uikit/loading-dots'
|
||||
import { extractErrorMessage } from '@penx/utils/extractErrorMessage'
|
||||
|
||||
const FormSchema = z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().min(6, {
|
||||
message: 'Password must be at least 6 characters.',
|
||||
}),
|
||||
})
|
||||
|
||||
interface Props {}
|
||||
|
||||
export function RegisterForm({}: Props) {
|
||||
const [isLoading, setLoading] = useState(false)
|
||||
const { setAuthStatus } = useAuthStatus()
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
email: '',
|
||||
password: '',
|
||||
},
|
||||
})
|
||||
|
||||
async function onSubmit(data: z.infer<typeof FormSchema>) {
|
||||
try {
|
||||
const sites = await localDB.listAllSites()
|
||||
const site = sites.find((s) => !s.props.isRemote)
|
||||
|
||||
const ref = searchParams?.get('ref') as string
|
||||
setLoading(true)
|
||||
await api.auth.registerByEmail.mutate({
|
||||
...data,
|
||||
ref: ref || '',
|
||||
userId: site?.userId,
|
||||
})
|
||||
|
||||
setAuthStatus({
|
||||
type: 'register-email-sent',
|
||||
data: {
|
||||
...data,
|
||||
ref: ref || '',
|
||||
userId: site?.userId,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.log('========error:', error)
|
||||
const msg = extractErrorMessage(error)
|
||||
toast.error(msg)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem className="w-full">
|
||||
<FormLabel>
|
||||
<Trans id="Email"></Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Email" {...field} className="w-full" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem className="w-full">
|
||||
<FormLabel>
|
||||
<Trans id="Password"></Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
{...field}
|
||||
className="w-full"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div>
|
||||
<Button
|
||||
size="lg"
|
||||
type="submit"
|
||||
className="w-full"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? <LoadingDots /> : <Trans id="Register"></Trans>}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div className="mt-2 text-center text-sm">
|
||||
<Trans id="Already have an account"></Trans>?{' '}
|
||||
<span
|
||||
className="text-brand"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setAuthStatus({ type: 'login' })
|
||||
}}
|
||||
>
|
||||
<Trans id="Log in"></Trans>
|
||||
</span>
|
||||
</div>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
import React from 'react'
|
||||
import { LoginForm } from '@/components/Profile/LoginForm'
|
||||
import { PinCodeForm } from '@/components/Profile/PinCodeForm'
|
||||
import { RegisterForm } from '@/components/Profile/RegisterForm'
|
||||
import { Capacitor } from '@capacitor/core'
|
||||
import {
|
||||
IonBackButton,
|
||||
@@ -10,42 +13,45 @@ import {
|
||||
IonTitle,
|
||||
IonToolbar,
|
||||
} from '@ionic/react'
|
||||
import { useAuthStatus } from '@penx/hooks/useAuthStatus'
|
||||
|
||||
const platform = Capacitor.getPlatform()
|
||||
|
||||
export function PageEmailLogin() {
|
||||
const { authStatus } = useAuthStatus()
|
||||
return (
|
||||
<>
|
||||
<IonHeader
|
||||
className={platform === 'android' ? 'safe-area' : ''}
|
||||
style={
|
||||
{
|
||||
boxShadow: '0 0 0 rgba(0, 0, 0, 0)',
|
||||
}
|
||||
}
|
||||
style={{
|
||||
boxShadow: '0 0 0 rgba(0, 0, 0, 0)',
|
||||
}}
|
||||
>
|
||||
<IonToolbar
|
||||
className="toolbar"
|
||||
style={
|
||||
{
|
||||
'--border-width': 0,
|
||||
// borderBottom: scrolled ? '1px solid #eeee' : 'none',
|
||||
// borderBottom: 'none',
|
||||
// border: 'none',
|
||||
}
|
||||
}
|
||||
style={{
|
||||
'--border-width': 0,
|
||||
// borderBottom: scrolled ? '1px solid #eeee' : 'none',
|
||||
// borderBottom: 'none',
|
||||
// border: 'none',
|
||||
}}
|
||||
>
|
||||
<IonButtons slot="start">
|
||||
<IonBackButton></IonBackButton>
|
||||
<IonBackButton color="dark" text=""></IonBackButton>
|
||||
</IonButtons>
|
||||
<IonTitle>Page Two</IonTitle>
|
||||
<IonTitle>Email login</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent class="ion-padding">
|
||||
<h1>Page Two</h1>
|
||||
{/* <IonNavLink routerDirection="forward" component={() => <PageThree />}>
|
||||
<IonButton>Go to Page Three</IonButton>
|
||||
</IonNavLink> */}
|
||||
<div className="flex h-full w-full flex-col justify-center">
|
||||
{authStatus.type === 'login' && <LoginForm></LoginForm>}
|
||||
|
||||
{authStatus.type === 'register' && <RegisterForm />}
|
||||
|
||||
{authStatus.type === 'register-email-sent' && (
|
||||
<PinCodeForm></PinCodeForm>
|
||||
)}
|
||||
</div>
|
||||
</IonContent>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { Footer } from '@/components/Footer'
|
||||
import { LoginContent } from '@/components/Login/LoginContent'
|
||||
import { MobileHome } from '@/components/MobileHome'
|
||||
import { SearchButton } from '@/components/MobileSearch/SearchButton'
|
||||
import { MobileTask } from '@/components/MobileTask/MobileTask'
|
||||
import { LoginContent } from '@/components/Profile/LoginContent'
|
||||
import { ProfileContent } from '@/components/Profile/ProfileContent'
|
||||
import { useHomeTab } from '@/hooks/useHomeTab'
|
||||
import { Capacitor } from '@capacitor/core'
|
||||
import { SplashScreen } from '@capacitor/splash-screen'
|
||||
@@ -40,6 +41,7 @@ import { appEmitter } from '@penx/emitter'
|
||||
import { useArea } from '@penx/hooks/useArea'
|
||||
import { useCreationId } from '@penx/hooks/useCreationId'
|
||||
import { ICreationNode } from '@penx/model-type'
|
||||
import { useSession } from '@penx/session'
|
||||
import { Button } from '@penx/uikit/button'
|
||||
import { Separator } from '@penx/uikit/separator'
|
||||
import { cn } from '@penx/utils'
|
||||
@@ -53,6 +55,7 @@ const PageHome: React.FC = ({ nav }: any) => {
|
||||
const { area } = useArea()
|
||||
const y = useMotionValue(0)
|
||||
const { isHome, type, setType } = useHomeTab()
|
||||
const { session } = useSession()
|
||||
|
||||
const inputRef = useRef<HTMLTextAreaElement>(null)
|
||||
|
||||
@@ -207,7 +210,8 @@ const PageHome: React.FC = ({ nav }: any) => {
|
||||
>
|
||||
{type === 'HOME' && <MobileHome />}
|
||||
{type === 'TASK' && <MobileTask />}
|
||||
{type === 'PROFILE' && <LoginContent />}
|
||||
{type === 'PROFILE' &&
|
||||
(session ? <ProfileContent /> : <LoginContent />)}
|
||||
</div>
|
||||
</IonContent>
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"@penx/local-db": "workspace:*",
|
||||
"@penx/model-type": "workspace:*",
|
||||
"@penx/domain": "workspace:*",
|
||||
"@penx/hooks": "workspace:*",
|
||||
"@penx/query-client": "workspace:*",
|
||||
"@penx/editor-transforms": "workspace:*",
|
||||
"@penx/contexts": "workspace:*",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { Trans } from '@lingui/react'
|
||||
import { useAuthStatus } from '@penx/hooks/useAuthStatus'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -11,7 +12,6 @@ import {
|
||||
import { LoginDialogContent } from './LoginDialogContent'
|
||||
import { PinCodeForm } from './PinCodeForm'
|
||||
import { RegisterForm } from './RegisterForm'
|
||||
import { useAuthStatus } from './useAuthStatus'
|
||||
import { useLoginDialog } from './useLoginDialog'
|
||||
|
||||
interface Props {}
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
'use client'
|
||||
|
||||
import { useCallback } from 'react'
|
||||
import {
|
||||
AuthKitProvider,
|
||||
SignInButton as FSignInButton,
|
||||
QRCode,
|
||||
StatusAPIResponse,
|
||||
useProfile,
|
||||
useSignIn,
|
||||
} from '@farcaster/auth-kit'
|
||||
import { Trans } from '@lingui/react'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import { toast } from 'sonner'
|
||||
@@ -19,10 +10,6 @@ import { LoginForm } from './LoginForm'
|
||||
import { useLoginDialog } from './useLoginDialog'
|
||||
|
||||
export function LoginDialogContent() {
|
||||
const { setIsOpen } = useLoginDialog()
|
||||
const { login, logout } = useSession()
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-3 pb-5">
|
||||
<div className="space-y-1">
|
||||
|
||||
@@ -6,6 +6,7 @@ import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { Trans } from '@lingui/react'
|
||||
import { toast } from 'sonner'
|
||||
import { z } from 'zod'
|
||||
import { useAuthStatus } from '@penx/hooks/useAuthStatus'
|
||||
import { useRouter } from '@penx/libs/i18n'
|
||||
import { useSession } from '@penx/session'
|
||||
import { Button } from '@penx/uikit/button'
|
||||
@@ -19,7 +20,6 @@ import {
|
||||
import { Input } from '@penx/uikit/input'
|
||||
import { LoadingDots } from '@penx/uikit/loading-dots'
|
||||
import { extractErrorMessage } from '@penx/utils/extractErrorMessage'
|
||||
import { useAuthStatus } from './useAuthStatus'
|
||||
import { useLoginDialog } from './useLoginDialog'
|
||||
|
||||
const FormSchema = z.object({
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Trans } from '@lingui/react'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import { toast } from 'sonner'
|
||||
import { z } from 'zod'
|
||||
import { useAuthStatus } from '@penx/hooks/useAuthStatus'
|
||||
import { localDB } from '@penx/local-db'
|
||||
import { useSession } from '@penx/session'
|
||||
import { api } from '@penx/trpc-client'
|
||||
@@ -28,7 +29,6 @@ import {
|
||||
InputOTPSlot,
|
||||
} from '@penx/uikit/ui/input-otp'
|
||||
import { extractErrorMessage } from '@penx/utils/extractErrorMessage'
|
||||
import { useAuthStatus } from './useAuthStatus'
|
||||
import { useLoginDialog } from './useLoginDialog'
|
||||
|
||||
const FormSchema = z.object({
|
||||
@@ -91,6 +91,7 @@ export function PinCodeForm({}: Props) {
|
||||
<Trans id="Login code"></Trans>
|
||||
</span>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="xs"
|
||||
onClick={async () => {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Trans } from '@lingui/react'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import { toast } from 'sonner'
|
||||
import { z } from 'zod'
|
||||
import { useAuthStatus } from '@penx/hooks/useAuthStatus'
|
||||
import { localDB } from '@penx/local-db'
|
||||
import { api } from '@penx/trpc-client'
|
||||
import { Button } from '@penx/uikit/button'
|
||||
@@ -21,7 +22,6 @@ import {
|
||||
import { Input } from '@penx/uikit/input'
|
||||
import { LoadingDots } from '@penx/uikit/loading-dots'
|
||||
import { extractErrorMessage } from '@penx/utils/extractErrorMessage'
|
||||
import { useAuthStatus } from './useAuthStatus'
|
||||
|
||||
const FormSchema = z.object({
|
||||
email: z.string().email(),
|
||||
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -2451,6 +2451,9 @@ importers:
|
||||
'@penx/editor-transforms':
|
||||
specifier: workspace:*
|
||||
version: link:../editor-transforms
|
||||
'@penx/hooks':
|
||||
specifier: workspace:*
|
||||
version: link:../hooks
|
||||
'@penx/libs':
|
||||
specifier: workspace:*
|
||||
version: link:../libs
|
||||
|
||||
Reference in New Issue
Block a user