forked from coracle/caravel
More stuff
This commit is contained in:
@@ -2,6 +2,7 @@ import { createEffect, Show } from "solid-js"
|
||||
import { Router, Route, useLocation, useNavigate } from "@solidjs/router"
|
||||
import type { Component } from "solid-js"
|
||||
import AppShell from "@/components/AppShell"
|
||||
import Toast from "@/components/Toast"
|
||||
import Home from "@/pages/Home"
|
||||
import RelayList from "@/pages/relays/RelayList"
|
||||
import RelayNew from "@/pages/relays/RelayNew"
|
||||
@@ -31,6 +32,7 @@ function Layout(props: { children?: any }) {
|
||||
<Show when={!identity.loading && identity() && usesAppShell()} fallback={<main>{props.children}</main>}>
|
||||
<AppShell>{props.children}</AppShell>
|
||||
</Show>
|
||||
<Toast />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ export default function Navbar() {
|
||||
const picture = useProfilePicture(() => account()?.pubkey)
|
||||
|
||||
return (
|
||||
<nav class="bg-white border-b border-gray-200">
|
||||
<nav class="fixed inset-0 h-screen bg-white border-b border-gray-200 z-40">
|
||||
<div class="max-w-4xl mx-auto px-4 h-14 flex items-center justify-between">
|
||||
<A href={account() ? "/relays" : "/"} class="flex items-center gap-2">
|
||||
<img src="/caravel.png" alt={PLATFORM_NAME} class="h-8 w-8 rounded-full object-cover" />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { A } from "@solidjs/router"
|
||||
import { For } from "solid-js"
|
||||
import { RELAY_PLANS, type RelayPlanId } from "@/lib/relayPlans"
|
||||
import { PLANS, type PlanId } from "@/lib/api"
|
||||
|
||||
function CheckIcon() {
|
||||
return (
|
||||
@@ -22,8 +22,8 @@ function XIcon() {
|
||||
|
||||
type PricingTableProps = {
|
||||
selectable?: boolean
|
||||
selectedPlan?: RelayPlanId
|
||||
onSelect?: (plan: RelayPlanId) => void
|
||||
selectedPlan?: PlanId
|
||||
onSelect?: (plan: PlanId) => void
|
||||
ctaHref?: string
|
||||
compactOnMobile?: boolean
|
||||
}
|
||||
@@ -31,7 +31,7 @@ type PricingTableProps = {
|
||||
export default function PricingTable(props: PricingTableProps) {
|
||||
return (
|
||||
<div class={`grid items-start ${props.compactOnMobile ? "grid-cols-3 gap-2 sm:grid-cols-1 sm:gap-6 md:grid-cols-3" : "grid-cols-1 md:grid-cols-3 gap-6"}`}>
|
||||
<For each={RELAY_PLANS}>
|
||||
<For each={PLANS}>
|
||||
{(plan) => {
|
||||
const isPopular = plan.id === "basic"
|
||||
const isSelected = () => props.selectable && props.selectedPlan === plan.id
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { A } from "@solidjs/router"
|
||||
import { Show, createEffect, createSignal, onCleanup } from "solid-js"
|
||||
import type { Relay } from "@/lib/api"
|
||||
import type { Relay, PlanId } from "@/lib/api"
|
||||
import menuDotsIcon from "@/assets/menu-dots-2.svg"
|
||||
import Modal from "@/components/Modal"
|
||||
import PricingTable from "@/components/PricingTable"
|
||||
import { RELAY_PLAN_IDS, type RelayPlanId } from "@/lib/relayPlans"
|
||||
|
||||
function Field(props: { label: string; children: any }) {
|
||||
return (
|
||||
@@ -89,8 +87,7 @@ type RelayDetailCardProps = {
|
||||
onToggleMediaStorage?: () => void
|
||||
onToggleLivekitSupport?: () => void
|
||||
onTogglePushNotifications?: () => void
|
||||
onUpdatePlan?: (plan: RelayPlanId) => Promise<void>
|
||||
updatingPlan?: boolean
|
||||
onUpdatePlan?: (plan: PlanId) => Promise<void>
|
||||
enforcePlanLimits?: boolean
|
||||
showPlanActions?: boolean
|
||||
}
|
||||
@@ -103,10 +100,8 @@ export default function RelayDetailCard(props: RelayDetailCardProps) {
|
||||
return fallback
|
||||
}
|
||||
const [menuOpen, setMenuOpen] = createSignal(false)
|
||||
const [planModalOpen, setPlanModalOpen] = createSignal(false)
|
||||
const [selectedPlan, setSelectedPlan] = createSignal<RelayPlanId>("free")
|
||||
const [planError, setPlanError] = createSignal("")
|
||||
const [submittingPlan, setSubmittingPlan] = createSignal(false)
|
||||
const [plan, setPlan] = createSignal<PlanId>(props.relay.plan)
|
||||
|
||||
let menuContainerRef: HTMLDivElement | undefined
|
||||
|
||||
const memberLimitByPlan: Record<string, string> = {
|
||||
@@ -116,32 +111,12 @@ export default function RelayDetailCard(props: RelayDetailCardProps) {
|
||||
}
|
||||
|
||||
const memberLimitLabel = () => memberLimitByPlan[r().plan] ?? "?"
|
||||
const isTopTier = () => r().plan === "growth"
|
||||
const planLimited = () => (props.enforcePlanLimits ?? true) && r().plan === "free"
|
||||
const showPlanActions = () => props.showPlanActions ?? true
|
||||
|
||||
createEffect(() => {
|
||||
if (!planModalOpen()) return
|
||||
const current = RELAY_PLAN_IDS.find((id) => id === r().plan) ?? "free"
|
||||
setSelectedPlan(current)
|
||||
setPlanError("")
|
||||
})
|
||||
|
||||
const canSubmitPlan = () => selectedPlan() !== r().plan
|
||||
|
||||
async function handlePlanContinue() {
|
||||
if (!props.onUpdatePlan || submittingPlan() || !canSubmitPlan()) return
|
||||
setPlanError("")
|
||||
setSubmittingPlan(true)
|
||||
|
||||
try {
|
||||
await props.onUpdatePlan(selectedPlan())
|
||||
setPlanModalOpen(false)
|
||||
} catch (e) {
|
||||
setPlanError(e instanceof Error ? e.message : "Failed to update plan")
|
||||
} finally {
|
||||
setSubmittingPlan(false)
|
||||
}
|
||||
async function changePlan(plan: PlanId) {
|
||||
setPlan(plan)
|
||||
props.onUpdatePlan?.(plan)
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
@@ -286,13 +261,9 @@ export default function RelayDetailCard(props: RelayDetailCardProps) {
|
||||
</A>
|
||||
}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center rounded-lg border border-blue-200 bg-blue-50 px-3 py-1.5 text-xs font-medium text-blue-700 hover:bg-blue-100"
|
||||
onClick={() => setPlanModalOpen(true)}
|
||||
>
|
||||
<span class="inline-flex items-center rounded-lg border border-blue-200 bg-blue-50 px-3 py-1.5 text-xs font-medium text-blue-700">
|
||||
Update Plan
|
||||
</button>
|
||||
</span>
|
||||
</Show>
|
||||
</Show>
|
||||
}
|
||||
@@ -319,13 +290,9 @@ export default function RelayDetailCard(props: RelayDetailCardProps) {
|
||||
</A>
|
||||
}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center rounded-lg border border-blue-200 bg-blue-50 px-3 py-1.5 text-xs font-medium text-blue-700 hover:bg-blue-100"
|
||||
onClick={() => setPlanModalOpen(true)}
|
||||
>
|
||||
<span class="inline-flex items-center rounded-lg border border-blue-200 bg-blue-50 px-3 py-1.5 text-xs font-medium text-blue-700">
|
||||
Update Plan
|
||||
</button>
|
||||
</span>
|
||||
</Show>
|
||||
</Show>
|
||||
}
|
||||
@@ -352,69 +319,31 @@ export default function RelayDetailCard(props: RelayDetailCardProps) {
|
||||
<span class="font-mono text-xs break-all">{r().tenant}</span>
|
||||
</Field>
|
||||
</Show>
|
||||
<Show when={props.editHref && showPlanActions()}>
|
||||
<Field label=" ">
|
||||
<Show
|
||||
when={props.onUpdatePlan}
|
||||
fallback={
|
||||
<Show
|
||||
when={!isTopTier()}
|
||||
fallback={<span />}
|
||||
>
|
||||
<A
|
||||
href={props.editHref!}
|
||||
class="inline-flex items-center rounded-lg border border-blue-200 bg-blue-50 px-3 py-1.5 text-xs font-medium text-blue-700 hover:bg-blue-100"
|
||||
>
|
||||
Upgrade Plan
|
||||
</A>
|
||||
</Show>
|
||||
}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center rounded-lg border border-blue-200 bg-blue-50 px-3 py-1.5 text-xs font-medium text-blue-700 hover:bg-blue-100"
|
||||
onClick={() => setPlanModalOpen(true)}
|
||||
>
|
||||
Update Plan
|
||||
</button>
|
||||
</Show>
|
||||
</Field>
|
||||
</Show>
|
||||
</MembershipSection>
|
||||
|
||||
<Modal
|
||||
open={planModalOpen()}
|
||||
onClose={() => setPlanModalOpen(false)}
|
||||
wrapperClass="fixed inset-0 z-40 flex items-center justify-center bg-black/40 p-4"
|
||||
panelClass="w-full max-w-5xl max-h-[90vh] overflow-y-auto rounded-2xl bg-white"
|
||||
>
|
||||
<div class="p-6 sm:p-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-2">Update plan</h2>
|
||||
<p class="text-sm text-gray-500 mb-8">Choose the plan you want for this relay.</p>
|
||||
<Show when={showPlanActions()}>
|
||||
<hr class="border-gray-200" />
|
||||
|
||||
<PricingTable
|
||||
selectable
|
||||
compactOnMobile
|
||||
selectedPlan={selectedPlan()}
|
||||
onSelect={setSelectedPlan}
|
||||
/>
|
||||
|
||||
<Show when={planError()}>
|
||||
<p class="mt-4 text-sm text-red-600">{planError()}</p>
|
||||
<DetailSection title="Plan">
|
||||
<Show
|
||||
when={props.onUpdatePlan}
|
||||
fallback={
|
||||
<Field label="Current plan">
|
||||
<span class="capitalize text-gray-900">{r().plan}</span>
|
||||
</Field>
|
||||
}
|
||||
>
|
||||
<div class="lg:col-span-2 space-y-4">
|
||||
<PricingTable
|
||||
selectable
|
||||
compactOnMobile
|
||||
selectedPlan={plan()}
|
||||
onSelect={changePlan}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<div class="mt-8">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => void handlePlanContinue()}
|
||||
disabled={!canSubmitPlan() || submittingPlan() || !!props.updatingPlan}
|
||||
class="w-full py-3 rounded-xl bg-blue-600 text-white font-semibold hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{submittingPlan() || props.updatingPlan ? "Updating..." : "Continue"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</DetailSection>
|
||||
</Show>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createEffect, createSignal } from "solid-js"
|
||||
import type { Relay } from "@/lib/hooks"
|
||||
import { slugify } from "@/lib/slugify"
|
||||
import { PLANS } from "@/lib/api"
|
||||
import { setToastMessage } from "@/components/Toast"
|
||||
|
||||
export type RelayFormValues = Pick<Relay, "info_name" | "subdomain" | "info_icon" | "info_description" | "plan">
|
||||
|
||||
@@ -14,17 +15,22 @@ type RelayFormProps = {
|
||||
}
|
||||
|
||||
export default function RelayForm(props: RelayFormProps) {
|
||||
const [plan, setPlan] = createSignal(props.initialValues?.plan ?? "")
|
||||
const [plan, setPlan] = createSignal(props.initialValues?.plan ?? PLANS[0].id)
|
||||
const [name, setName] = createSignal(props.initialValues?.info_name ?? "")
|
||||
const [subdomain, setSubdomain] = createSignal(props.initialValues?.subdomain ?? "")
|
||||
const [icon, setIcon] = createSignal(props.initialValues?.info_icon ?? "")
|
||||
const [description, setDescription] = createSignal(props.initialValues?.info_description ?? "")
|
||||
const [submitting, setSubmitting] = createSignal(false)
|
||||
const [error, setError] = createSignal("")
|
||||
|
||||
async function handleSubmit(e: Event) {
|
||||
e.preventDefault()
|
||||
setError("")
|
||||
|
||||
if (!plan()) {
|
||||
setToastMessage("Please select a plan")
|
||||
return
|
||||
}
|
||||
|
||||
setToastMessage("")
|
||||
setSubmitting(true)
|
||||
|
||||
try {
|
||||
@@ -36,7 +42,7 @@ export default function RelayForm(props: RelayFormProps) {
|
||||
info_description: description(),
|
||||
})
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : "Failed to save relay")
|
||||
setToastMessage(e instanceof Error ? e.message : "Failed to save relay")
|
||||
} finally {
|
||||
setSubmitting(false)
|
||||
}
|
||||
@@ -106,12 +112,11 @@ export default function RelayForm(props: RelayFormProps) {
|
||||
<div class="text-sm text-gray-500 mt-1">
|
||||
{p.price === 0 ? "Free" : `${p.price.toLocaleString()} sats/mo`}
|
||||
</div>
|
||||
<div class="text-xs text-gray-500 mt-2">{p.members} members</div>
|
||||
<div class="text-xs text-gray-500 mt-2">{p.memberLabel}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{error() && <p class="text-sm text-red-600">{error()}</p>}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={submitting()}
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import { Show, createEffect, createSignal, onCleanup } from "solid-js"
|
||||
|
||||
type ToastProps = {
|
||||
message?: string
|
||||
duration?: number
|
||||
onClear?: () => void
|
||||
}
|
||||
export const [toastMessage, setToastMessage] = createSignal("")
|
||||
|
||||
export default function Toast(props: ToastProps) {
|
||||
export default function Toast() {
|
||||
const [visible, setVisible] = createSignal(false)
|
||||
|
||||
let hideTimer: number | undefined
|
||||
@@ -26,7 +22,7 @@ export default function Toast(props: ToastProps) {
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
const message = props.message?.trim()
|
||||
const message = toastMessage()?.trim()
|
||||
clearTimers()
|
||||
|
||||
if (!message) {
|
||||
@@ -46,11 +42,11 @@ export default function Toast(props: ToastProps) {
|
||||
hideTimer = window.setTimeout(() => {
|
||||
setVisible(false)
|
||||
clearTimer = window.setTimeout(() => {
|
||||
props.onClear?.()
|
||||
setToastMessage("")
|
||||
clearTimer = undefined
|
||||
}, 250)
|
||||
hideTimer = undefined
|
||||
}, props.duration ?? 10_000)
|
||||
}, 10_000)
|
||||
})
|
||||
|
||||
onCleanup(() => {
|
||||
@@ -58,7 +54,7 @@ export default function Toast(props: ToastProps) {
|
||||
})
|
||||
|
||||
return (
|
||||
<Show when={props.message}>
|
||||
<Show when={toastMessage()}>
|
||||
<div
|
||||
role="alert"
|
||||
class="fixed bottom-4 right-4 z-50 max-w-md rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-base text-red-700 shadow-lg transition-all duration-400 ease-out"
|
||||
@@ -67,7 +63,7 @@ export default function Toast(props: ToastProps) {
|
||||
"translate-y-3 opacity-0 scale-95": !visible(),
|
||||
}}
|
||||
>
|
||||
{props.message}
|
||||
{toastMessage()}
|
||||
</div>
|
||||
</Show>
|
||||
)
|
||||
|
||||
+31
-4
@@ -32,9 +32,36 @@ export class ApiError extends Error {
|
||||
export type Plan = Record<string, unknown>
|
||||
|
||||
export const PLANS = [
|
||||
{ id: "free", label: "Free", price: 0, members: "Up to 10", blossom: false, livekit: false },
|
||||
{ id: "basic", label: "Basic", price: 10_000, members: "Up to 100", blossom: true, livekit: true },
|
||||
{ id: "growth", label: "Growth", price: 50_000, members: "Unlimited", blossom: true, livekit: true },
|
||||
{
|
||||
id: "free",
|
||||
label: "Free",
|
||||
subtitle: "Get started, no commitment.",
|
||||
price: 0,
|
||||
priceLabel: "0",
|
||||
memberLabel: "Up to 10 members",
|
||||
blossom: false,
|
||||
livekit: false,
|
||||
},
|
||||
{
|
||||
id: "basic",
|
||||
label: "Basic",
|
||||
subtitle: "For growing communities.",
|
||||
price: 10_000,
|
||||
priceLabel: "10K",
|
||||
memberLabel: "Up to 100 members",
|
||||
blossom: true,
|
||||
livekit: true,
|
||||
},
|
||||
{
|
||||
id: "growth",
|
||||
label: "Growth",
|
||||
subtitle: "For large-scale communities.",
|
||||
price: 50_000,
|
||||
priceLabel: "50K",
|
||||
memberLabel: "Unlimited members",
|
||||
blossom: true,
|
||||
livekit: true,
|
||||
},
|
||||
] as const
|
||||
|
||||
export type PlanId = (typeof PLANS)[number]["id"]
|
||||
@@ -44,7 +71,7 @@ export type Relay = {
|
||||
tenant: string
|
||||
schema: string
|
||||
subdomain: string
|
||||
plan: string
|
||||
plan: PlanId
|
||||
status: string
|
||||
sync_error: string
|
||||
info_name: string
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
export const RELAY_PLAN_IDS = ["free", "basic", "growth"] as const
|
||||
|
||||
export type RelayPlanId = (typeof RELAY_PLAN_IDS)[number]
|
||||
|
||||
export const RELAY_PLANS = [
|
||||
{
|
||||
id: "free",
|
||||
label: "Free",
|
||||
subtitle: "Get started, no commitment.",
|
||||
price: 0,
|
||||
priceLabel: "0",
|
||||
memberLabel: "Up to 10 members",
|
||||
blossom: false,
|
||||
livekit: false,
|
||||
},
|
||||
{
|
||||
id: "basic",
|
||||
label: "Basic",
|
||||
subtitle: "For growing communities.",
|
||||
price: 10_000,
|
||||
priceLabel: "10K",
|
||||
memberLabel: "Up to 100 members",
|
||||
blossom: true,
|
||||
livekit: true,
|
||||
},
|
||||
{
|
||||
id: "growth",
|
||||
label: "Growth",
|
||||
subtitle: "For large-scale communities.",
|
||||
price: 50_000,
|
||||
priceLabel: "50K",
|
||||
memberLabel: "Unlimited members",
|
||||
blossom: true,
|
||||
livekit: true,
|
||||
},
|
||||
] as const satisfies readonly {
|
||||
id: RelayPlanId
|
||||
label: string
|
||||
subtitle: string
|
||||
price: number
|
||||
priceLabel: string
|
||||
memberLabel: string
|
||||
blossom: boolean
|
||||
livekit: boolean
|
||||
}[]
|
||||
@@ -22,6 +22,7 @@ export default function Home() {
|
||||
navigate(`/relays/${relay.id}`)
|
||||
} else {
|
||||
setDraftRelay(values)
|
||||
setShowRelayModal(false)
|
||||
setShowLoginModal(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useParams } from "@solidjs/router"
|
||||
import { createMemo, createResource, createSignal, Show } from "solid-js"
|
||||
import type { RelayPlanId } from "@/lib/relayPlans"
|
||||
import type { PlanId } from "@/lib/api"
|
||||
import BackLink from "@/components/BackLink"
|
||||
import PageContainer from "@/components/PageContainer"
|
||||
import RelayDetailCard from "@/components/RelayDetailCard"
|
||||
@@ -131,7 +131,7 @@ export default function RelayDetail() {
|
||||
void updateRelay(next, current)
|
||||
}
|
||||
|
||||
async function handleUpdatePlan(plan: RelayPlanId) {
|
||||
async function handleUpdatePlan(plan: PlanId) {
|
||||
const current = relay()
|
||||
if (!current) return
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ export default function RelayNew() {
|
||||
<div class="text-sm text-gray-500 mt-1">
|
||||
{p.price === 0 ? "Free" : `${p.price.toLocaleString()} sats/mo`}
|
||||
</div>
|
||||
<div class="text-xs text-gray-500 mt-2">{p.members} members</div>
|
||||
<div class="text-xs text-gray-500 mt-2">{p.memberLabel}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { PasswordSigner } from "applesauce-signers"
|
||||
import QrScanner from "qr-scanner"
|
||||
import QRCode from "qrcode"
|
||||
import { accountManager, identity, PLATFORM_NAME } from "@/lib/state"
|
||||
import useMinLoading from "@/components/useMinLoading"
|
||||
|
||||
const NIP46_RELAYS = ['wss://bucket.coracle.social', 'wss://ephemeral.snowflare.cc']
|
||||
|
||||
@@ -46,7 +47,8 @@ type LoginPageProps = LoginProps & Partial<RouteSectionProps<unknown>>
|
||||
export default function Login(props: LoginPageProps = {}) {
|
||||
const navigate = useNavigate()
|
||||
const [tab, setTab] = createSignal<Tab>(window.nostr ? "nip07" : "nip46")
|
||||
const [loading, setLoading] = createSignal(false)
|
||||
const [rawLoading, setRawLoading] = createSignal(false)
|
||||
const loading = useMinLoading(() => rawLoading())
|
||||
const [error, setError] = createSignal("")
|
||||
const [screen, setScreen] = createSignal<Screen>("tabs")
|
||||
|
||||
@@ -72,19 +74,19 @@ export default function Login(props: LoginPageProps = {}) {
|
||||
|
||||
async function loginWithNip07() {
|
||||
setError("")
|
||||
setLoading(true)
|
||||
setRawLoading(true)
|
||||
try {
|
||||
await completeLogin(await ExtensionAccount.fromExtension())
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : "Failed to login with extension")
|
||||
} finally {
|
||||
setLoading(false)
|
||||
setRawLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
async function startNostrConnect() {
|
||||
setError("")
|
||||
setLoading(true)
|
||||
setRawLoading(true)
|
||||
|
||||
try {
|
||||
const NostrConnectSigner = await loadNostrConnectSigner()
|
||||
@@ -110,13 +112,13 @@ export default function Login(props: LoginPageProps = {}) {
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : "Failed to connect signer")
|
||||
} finally {
|
||||
setLoading(false)
|
||||
setRawLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
async function loginWithBunker() {
|
||||
setError("")
|
||||
setLoading(true)
|
||||
setRawLoading(true)
|
||||
try {
|
||||
const uri = normalizeBunkerUrl(bunkerUrl())
|
||||
const NostrConnectSigner = await loadNostrConnectSigner()
|
||||
@@ -127,13 +129,13 @@ export default function Login(props: LoginPageProps = {}) {
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : "Invalid bunker URL")
|
||||
} finally {
|
||||
setLoading(false)
|
||||
setRawLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
async function loginWithKeyMaterial() {
|
||||
setError("")
|
||||
setLoading(true)
|
||||
setRawLoading(true)
|
||||
try {
|
||||
if (ncryptsecValue().trim()) {
|
||||
if (!password().trim()) {
|
||||
@@ -153,7 +155,7 @@ export default function Login(props: LoginPageProps = {}) {
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : "Invalid key")
|
||||
} finally {
|
||||
setLoading(false)
|
||||
setRawLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user