Adds scheduled events to the feed

Implements NIP-52 scheduled events, allowing users to view and interact with calendar events.

A new `ScheduledEventService` is introduced to manage fetching, storing, and completing scheduled events. A new `ScheduledEventCard` component is introduced for displaying the scheduled events.
This commit is contained in:
padreug 2025-10-21 21:58:58 +02:00
parent b6d8a78cd8
commit 9b05bcc238
8 changed files with 716 additions and 1 deletions

View file

@ -13,9 +13,12 @@ import { Megaphone, RefreshCw, AlertCircle } from 'lucide-vue-next'
import { useFeed } from '../composables/useFeed'
import { useProfiles } from '../composables/useProfiles'
import { useReactions } from '../composables/useReactions'
import { useScheduledEvents } from '../composables/useScheduledEvents'
import ThreadedPost from './ThreadedPost.vue'
import ScheduledEventCard from './ScheduledEventCard.vue'
import appConfig from '@/app.config'
import type { ContentFilter, FeedPost } from '../services/FeedService'
import type { ScheduledEvent } from '../services/ScheduledEventService'
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
import type { AuthService } from '@/modules/base/auth/auth-service'
import type { RelayHub } from '@/modules/base/nostr/relay-hub'
@ -95,6 +98,12 @@ const { getDisplayName, fetchProfiles } = useProfiles()
// Use reactions service for likes/hearts
const { getEventReactions, subscribeToReactions, toggleLike } = useReactions()
// Use scheduled events service
const { getTodaysEvents, getCompletion, toggleComplete } = useScheduledEvents()
// Get today's scheduled events (reactive)
const todaysScheduledEvents = computed(() => getTodaysEvents())
// Watch for new posts and fetch their profiles and reactions
watch(notes, async (newNotes) => {
if (newNotes.length > 0) {
@ -158,6 +167,15 @@ async function onToggleLike(note: FeedPost) {
}
}
// Handle scheduled event completion toggle
async function onToggleComplete(event: ScheduledEvent) {
try {
await toggleComplete(event)
} catch (error) {
console.error('Failed to toggle event completion:', error)
}
}
// Handle collapse toggle with cascading behavior
function onToggleCollapse(postId: string) {
const newCollapsed = new Set(collapsedPosts.value)
@ -369,7 +387,29 @@ function cancelDelete() {
<!-- Posts List - Natural flow without internal scrolling -->
<div v-else>
<div class="md:space-y-4 md:py-4">
<!-- Today's Scheduled Events Section -->
<div v-if="todaysScheduledEvents.length > 0" class="mb-6 md:mb-8">
<h3 class="text-sm font-semibold text-muted-foreground uppercase tracking-wide px-4 md:px-0 mb-3">
📅 Today's Events
</h3>
<div class="md:space-y-3">
<ScheduledEventCard
v-for="event in todaysScheduledEvents"
:key="`${event.pubkey}:${event.dTag}`"
:event="event"
:completion="getCompletion(`31922:${event.pubkey}:${event.dTag}`)"
:get-display-name="getDisplayName"
:admin-pubkeys="adminPubkeys"
@toggle-complete="onToggleComplete"
/>
</div>
</div>
<!-- Posts Section -->
<div v-if="threadedPosts.length > 0" class="md:space-y-4 md:py-4">
<h3 v-if="todaysScheduledEvents.length > 0" class="text-sm font-semibold text-muted-foreground uppercase tracking-wide px-4 md:px-0 mb-3 mt-6">
💬 Posts
</h3>
<ThreadedPost
v-for="post in threadedPosts"
:key="post.id"