feat: outbox model for the following feed

This commit is contained in:
codytseng
2025-03-27 22:37:06 +08:00
parent df4eb10802
commit d24e208f0b
22 changed files with 642 additions and 517 deletions

View File

@@ -0,0 +1,56 @@
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { useNostr } from '@/providers/NostrProvider'
import { Loader } from 'lucide-react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
export default function NpubLogin({
back,
onLoginSuccess
}: {
back: () => void
onLoginSuccess: () => void
}) {
const { t } = useTranslation()
const { npubLogin } = useNostr()
const [pending, setPending] = useState(false)
const [npubInput, setNpubInput] = useState('')
const [errMsg, setErrMsg] = useState<string | null>(null)
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setNpubInput(e.target.value)
setErrMsg(null)
}
const handleLogin = () => {
if (npubInput === '') return
setPending(true)
npubLogin(npubInput)
.then(() => onLoginSuccess())
.catch((err) => setErrMsg(err.message))
.finally(() => setPending(false))
}
return (
<>
<div className="space-y-1">
<Input
placeholder="npub..."
value={npubInput}
onChange={handleInputChange}
className={errMsg ? 'border-destructive' : ''}
/>
{errMsg && <div className="text-xs text-destructive pl-3">{errMsg}</div>}
</div>
<Button onClick={handleLogin} disabled={pending}>
<Loader className={pending ? 'animate-spin' : 'hidden'} />
{t('Login')}
</Button>
<Button variant="secondary" onClick={back}>
{t('Back')}
</Button>
</>
)
}

View File

@@ -8,9 +8,11 @@ import { useTranslation } from 'react-i18next'
import AccountList from '../AccountList'
import BunkerLogin from './BunkerLogin'
import GenerateNewAccount from './GenerateNewAccount'
import NpubLogin from './NpubLogin'
import PrivateKeyLogin from './PrivateKeyLogin'
import { isDevEnv } from '@/lib/common'
type TAccountManagerPage = 'nsec' | 'bunker' | 'generate' | null
type TAccountManagerPage = 'nsec' | 'bunker' | 'generate' | 'npub' | null
export default function AccountManager({ close }: { close?: () => void }) {
const [page, setPage] = useState<TAccountManagerPage>(null)
@@ -23,6 +25,8 @@ export default function AccountManager({ close }: { close?: () => void }) {
<BunkerLogin back={() => setPage(null)} onLoginSuccess={() => close?.()} />
) : page === 'generate' ? (
<GenerateNewAccount back={() => setPage(null)} onLoginSuccess={() => close?.()} />
) : page === 'npub' ? (
<NpubLogin back={() => setPage(null)} onLoginSuccess={() => close?.()} />
) : (
<AccountManagerNav setPage={setPage} close={close} />
)}
@@ -59,6 +63,11 @@ function AccountManagerNav({
<Button variant="secondary" onClick={() => setPage('nsec')} className="w-full">
{t('Login with Private Key')}
</Button>
{isDevEnv() && (
<Button variant="secondary" onClick={() => setPage('npub')} className="w-full">
Login with Public key (for development)
</Button>
)}
</div>
</div>
<Separator />