Enables recurring scheduled event completion

Extends scheduled event completion to support recurring events.

The changes introduce the concept of an "occurrence" for recurring events,
allowing users to mark individual instances of a recurring event as complete.
This involves:
- Adding recurrence information to the ScheduledEvent model.
- Modifying completion logic to handle recurring events with daily/weekly frequencies
- Updating UI to display recurrence information and mark individual occurrences as complete.
This commit is contained in:
padreug 2025-10-22 00:16:47 +02:00
parent 8381d43268
commit 706ceea84b
4 changed files with 147 additions and 46 deletions

View file

@ -200,10 +200,10 @@ async function onToggleLike(note: FeedPost) {
}
// Handle scheduled event completion toggle
async function onToggleComplete(event: ScheduledEvent) {
console.log('🎯 NostrFeed: onToggleComplete called for event:', event.title)
async function onToggleComplete(event: ScheduledEvent, occurrence?: string) {
console.log('🎯 NostrFeed: onToggleComplete called for event:', event.title, 'occurrence:', occurrence)
try {
await toggleComplete(event)
await toggleComplete(event, occurrence)
console.log('✅ NostrFeed: toggleComplete succeeded')
} catch (error) {
console.error('❌ NostrFeed: Failed to toggle event completion:', error)

View file

@ -21,12 +21,12 @@ import type { ScheduledEvent, EventCompletion } from '../services/ScheduledEvent
interface Props {
event: ScheduledEvent
getDisplayName: (pubkey: string) => string
getCompletion: (eventAddress: string) => EventCompletion | undefined
getCompletion: (eventAddress: string, occurrence?: string) => EventCompletion | undefined
adminPubkeys?: string[]
}
interface Emits {
(e: 'toggle-complete', event: ScheduledEvent): void
(e: 'toggle-complete', event: ScheduledEvent, occurrence?: string): void
}
const props = withDefaults(defineProps<Props>(), {
@ -41,11 +41,20 @@ const showConfirmDialog = ref(false)
// Event address for tracking completion
const eventAddress = computed(() => `31922:${props.event.pubkey}:${props.event.dTag}`)
// Check if this is a recurring event
const isRecurring = computed(() => !!props.event.recurrence)
// For recurring events, occurrence is today's date. For non-recurring, it's undefined.
const occurrence = computed(() => {
if (!isRecurring.value) return undefined
return new Date().toISOString().split('T')[0] // YYYY-MM-DD
})
// Check if this is an admin event
const isAdminEvent = computed(() => props.adminPubkeys.includes(props.event.pubkey))
// Check if event is completed - call function directly
const isCompleted = computed(() => props.getCompletion(eventAddress.value)?.completed || false)
// Check if event is completed - call function with occurrence for recurring events
const isCompleted = computed(() => props.getCompletion(eventAddress.value, occurrence.value)?.completed || false)
// Check if event is completable (task type)
const isCompletable = computed(() => props.event.eventType === 'task')
@ -109,8 +118,8 @@ function handleMarkComplete() {
// Confirm and execute mark complete
function confirmMarkComplete() {
console.log('✅ Confirmed mark complete for event:', props.event.title)
emit('toggle-complete', props.event)
console.log('✅ Confirmed mark complete for event:', props.event.title, 'occurrence:', occurrence.value)
emit('toggle-complete', props.event, occurrence.value)
showConfirmDialog.value = false
}
@ -152,8 +161,13 @@ function cancelMarkComplete() {
</Button>
<!-- Completed Badge with completer name -->
<Badge v-if="isCompletable && isCompleted && getCompletion(eventAddress)" variant="secondary" class="text-xs">
{{ getDisplayName(getCompletion(eventAddress)!.pubkey) }}
<Badge v-if="isCompletable && isCompleted && getCompletion(eventAddress, occurrence)" variant="secondary" class="text-xs">
{{ getDisplayName(getCompletion(eventAddress, occurrence)!.pubkey) }}
</Badge>
<!-- Recurring Badge -->
<Badge v-if="isRecurring" variant="outline" class="text-xs">
🔄
</Badge>
<!-- Admin Badge -->
@ -192,9 +206,9 @@ function cancelMarkComplete() {
</div>
<!-- Completion info (only for completable events) -->
<div v-if="isCompletable && isCompleted && getCompletion(eventAddress)" class="text-xs text-muted-foreground mb-3">
Completed by {{ getDisplayName(getCompletion(eventAddress)!.pubkey) }}
<span v-if="getCompletion(eventAddress)!.notes"> - {{ getCompletion(eventAddress)!.notes }}</span>
<div v-if="isCompletable && isCompleted && getCompletion(eventAddress, occurrence)" class="text-xs text-muted-foreground mb-3">
Completed by {{ getDisplayName(getCompletion(eventAddress, occurrence)!.pubkey) }}
<span v-if="getCompletion(eventAddress, occurrence)!.notes"> - {{ getCompletion(eventAddress, occurrence)!.notes }}</span>
</div>
<!-- Author (if not admin) -->