Enhance payment processing and rental features

- Updated the BTCPay service to support internal Lightning invoices with private route hints, improving payment routing for users with private channels.
- Added reconciliation methods for pending rents and subscriptions to ensure missed payments are processed on startup.
- Enhanced the rental and subscription services to handle payments in satoshis, aligning with Lightning Network standards.
- Improved the rental modal and content detail components to display rental status and pricing more clearly, including a countdown for rental expiration.
- Refactored various components to streamline user experience and ensure accurate rental access checks.
This commit is contained in:
Dorian
2026-02-12 23:24:25 +00:00
parent cdd24a5def
commit 0da83f461c
39 changed files with 1182 additions and 270 deletions

View File

@@ -74,7 +74,7 @@
<!-- Right Side Actions -->
<div class="flex items-center gap-4">
<!-- Nostr Login (persona switcher or extension) -->
<div v-if="!nostrLoggedIn" class="hidden md:flex items-center gap-2">
<div v-if="!hasNostrSession" class="hidden md:flex items-center gap-2">
<!-- Persona Switcher (dev) -->
<div class="relative persona-dropdown">
<button @click="togglePersonaMenu" class="nav-button px-3 py-2 text-xs">
@@ -118,7 +118,7 @@
<!-- Sign In (app auth, if not Nostr logged in) -->
<button
v-if="!isAuthenticated && showAuth && !nostrLoggedIn"
v-if="!isAuthenticated && showAuth && !hasNostrSession"
@click="$emit('openAuth')"
class="hidden md:block hero-play-button px-4 py-2 text-sm"
>
@@ -189,7 +189,7 @@
</div>
<!-- Active Nostr Account -->
<div v-if="nostrLoggedIn" class="hidden md:block relative profile-dropdown">
<div v-if="hasNostrSession" class="hidden md:block relative profile-dropdown">
<button
@click="toggleDropdown"
class="profile-button flex items-center gap-2"
@@ -270,12 +270,12 @@
<!-- Mobile -->
<div class="md:hidden flex items-center gap-2 mr-2">
<img
v-if="nostrLoggedIn && nostrActivePubkey"
v-if="hasNostrSession && nostrActivePubkey"
:src="`https://robohash.org/${nostrActivePubkey}.png`"
class="w-7 h-7 rounded-full"
alt="Avatar"
/>
<span v-if="nostrLoggedIn" class="text-white text-sm font-medium">{{ nostrActiveName }}</span>
<span v-if="hasNostrSession" class="text-white text-sm font-medium">{{ nostrActiveName }}</span>
<template v-else-if="isAuthenticated">
<div class="w-7 h-7 rounded-full bg-gradient-to-br from-orange-500 to-pink-500 flex items-center justify-center text-xs font-bold text-white">
{{ userInitials }}
@@ -350,6 +350,20 @@ const contentSourceStore = useContentSourceStore()
const contentStore = useContentStore()
const isFilmmakerUser = isFilmmakerComputed
/**
* Treat the user as "truly Nostr-logged-in" only when the
* accountManager has an active account AND there's a matching
* session token. This prevents showing a stale profile pill
* after site data has been cleared.
*/
const hasNostrSession = computed(() => {
if (!nostrLoggedIn.value) return false
// If we also have a backend session, the login is genuine
if (isAuthenticated.value) return true
// Otherwise verify there's at least a stored token to back the account
return !!(sessionStorage.getItem('nostr_token') || sessionStorage.getItem('auth_token'))
})
/** Switch content source and reload */
function handleSourceSelect(sourceId: string) {
contentSourceStore.setSource(sourceId as any)
@@ -520,7 +534,7 @@ function handleMyListClick() {
if (activeAlgorithm.value) {
_setAlgorithm(activeAlgorithm.value as any) // toggle off
}
if (!isAuthenticated.value && !nostrLoggedIn.value) {
if (!isAuthenticated.value && !hasNostrSession.value) {
emit('openAuth', '/library')
return
}
@@ -553,8 +567,10 @@ async function handlePersonaLogin(persona: Persona) {
// Also populate auth store (for subscription/My List access)
try {
await appLoginWithNostr(persona.pubkey, 'persona', {})
} catch {
// Auth store mock login — non-critical if it fails
} catch (err) {
// Backend auth failed — persona still works for commenting/reactions
// via accountManager, just won't have full API access
console.warn('[PersonaLogin] Backend auth failed:', (err as Error).message)
}
}