Enables marking scheduled events as complete
Implements a feature to mark scheduled events as complete, replacing the checkbox with a button for improved UX. This commit enhances the Scheduled Events functionality by allowing users to mark events as complete. It also includes: - Replaces the checkbox with a "Mark Complete" button for better usability. - Adds logging for debugging purposes during event completion toggling. - Routes completion events (kind 31925) to the ScheduledEventService. - Optimistically updates the local state after publishing completion events.
This commit is contained in:
parent
b15a8c21c0
commit
5d6f702859
5 changed files with 91 additions and 60 deletions
|
|
@ -1,14 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Checkbox } from '@/components/ui/checkbox'
|
||||
import { Calendar, MapPin, Clock } from 'lucide-vue-next'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Calendar, MapPin, Clock, CheckCircle } from 'lucide-vue-next'
|
||||
import type { ScheduledEvent, EventCompletion } from '../services/ScheduledEventService'
|
||||
|
||||
interface Props {
|
||||
event: ScheduledEvent
|
||||
completion?: EventCompletion
|
||||
getDisplayName: (pubkey: string) => string
|
||||
getCompletion: (eventAddress: string) => EventCompletion | undefined
|
||||
adminPubkeys?: string[]
|
||||
}
|
||||
|
||||
|
|
@ -22,11 +22,14 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// Event address for tracking completion
|
||||
const eventAddress = computed(() => `31922:${props.event.pubkey}:${props.event.dTag}`)
|
||||
|
||||
// Check if this is an admin event
|
||||
const isAdminEvent = computed(() => props.adminPubkeys.includes(props.event.pubkey))
|
||||
|
||||
// Check if event is completed
|
||||
const isCompleted = computed(() => props.completion?.completed || false)
|
||||
// Check if event is completed - call function directly
|
||||
const isCompleted = computed(() => props.getCompletion(eventAddress.value)?.completed || false)
|
||||
|
||||
// Format the date/time
|
||||
const formattedDate = computed(() => {
|
||||
|
|
@ -79,8 +82,9 @@ const formattedTimeRange = computed(() => {
|
|||
}
|
||||
})
|
||||
|
||||
// Handle checkbox toggle
|
||||
function handleToggleComplete() {
|
||||
// Handle mark complete button click
|
||||
function handleMarkComplete() {
|
||||
console.log('🔘 Mark Complete button clicked for event:', props.event.title)
|
||||
emit('toggle-complete', props.event)
|
||||
}
|
||||
</script>
|
||||
|
|
@ -88,63 +92,64 @@ function handleToggleComplete() {
|
|||
<template>
|
||||
<div class="border-b md:border md:rounded-lg bg-card p-4 md:p-6 transition-all"
|
||||
:class="{ 'opacity-60': isCompleted }">
|
||||
<!-- Header -->
|
||||
<div class="flex items-start gap-3 mb-3">
|
||||
<!-- Completion Checkbox -->
|
||||
<div class="flex items-center pt-1">
|
||||
<Checkbox
|
||||
:checked="isCompleted"
|
||||
@update:checked="handleToggleComplete"
|
||||
class="h-5 w-5"
|
||||
/>
|
||||
<!-- Event Details -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<!-- Title and badges -->
|
||||
<div class="flex items-start gap-2 mb-2 flex-wrap">
|
||||
<h3 class="font-semibold text-base md:text-lg flex-1"
|
||||
:class="{ 'line-through': isCompleted }">
|
||||
{{ event.title }}
|
||||
</h3>
|
||||
<Badge v-if="isAdminEvent" variant="secondary" class="shrink-0">
|
||||
Admin
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
<!-- Event Details -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<!-- Title and badges -->
|
||||
<div class="flex items-start gap-2 mb-2 flex-wrap">
|
||||
<h3 class="font-semibold text-base md:text-lg flex-1"
|
||||
:class="{ 'line-through': isCompleted }">
|
||||
{{ event.title }}
|
||||
</h3>
|
||||
<Badge v-if="isAdminEvent" variant="secondary" class="shrink-0">
|
||||
Admin
|
||||
</Badge>
|
||||
<!-- Date/Time -->
|
||||
<div class="flex items-center gap-4 text-sm text-muted-foreground mb-2 flex-wrap">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<Calendar class="h-4 w-4" />
|
||||
<span>{{ formattedDate }}</span>
|
||||
</div>
|
||||
<div v-if="formattedTimeRange" class="flex items-center gap-1.5">
|
||||
<Clock class="h-4 w-4" />
|
||||
<span>{{ formattedTimeRange }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Date/Time -->
|
||||
<div class="flex items-center gap-4 text-sm text-muted-foreground mb-2 flex-wrap">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<Calendar class="h-4 w-4" />
|
||||
<span>{{ formattedDate }}</span>
|
||||
</div>
|
||||
<div v-if="formattedTimeRange" class="flex items-center gap-1.5">
|
||||
<Clock class="h-4 w-4" />
|
||||
<span>{{ formattedTimeRange }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Location -->
|
||||
<div v-if="event.location" class="flex items-center gap-1.5 text-sm text-muted-foreground mb-3">
|
||||
<MapPin class="h-4 w-4" />
|
||||
<span>{{ event.location }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Location -->
|
||||
<div v-if="event.location" class="flex items-center gap-1.5 text-sm text-muted-foreground mb-3">
|
||||
<MapPin class="h-4 w-4" />
|
||||
<span>{{ event.location }}</span>
|
||||
</div>
|
||||
<!-- Description/Content -->
|
||||
<div v-if="event.description || event.content" class="text-sm mb-3">
|
||||
<p class="whitespace-pre-wrap break-words">{{ event.description || event.content }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Description/Content -->
|
||||
<div v-if="event.description || event.content" class="text-sm mb-3">
|
||||
<p class="whitespace-pre-wrap break-words">{{ event.description || event.content }}</p>
|
||||
</div>
|
||||
<!-- Completion info -->
|
||||
<div v-if="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>
|
||||
|
||||
<!-- Completion info -->
|
||||
<div v-if="isCompleted && completion" class="text-xs text-muted-foreground">
|
||||
✓ Completed by {{ getDisplayName(completion.pubkey) }}
|
||||
<span v-if="completion.notes"> - {{ completion.notes }}</span>
|
||||
</div>
|
||||
<!-- Author (if not admin) -->
|
||||
<div v-if="!isAdminEvent" class="text-xs text-muted-foreground mb-3">
|
||||
Posted by {{ getDisplayName(event.pubkey) }}
|
||||
</div>
|
||||
|
||||
<!-- Author (if not admin) -->
|
||||
<div v-if="!isAdminEvent" class="text-xs text-muted-foreground mt-2">
|
||||
Posted by {{ getDisplayName(event.pubkey) }}
|
||||
</div>
|
||||
<!-- Mark Complete Button -->
|
||||
<div v-if="!isCompleted" class="mt-3">
|
||||
<Button
|
||||
@click="handleMarkComplete"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="gap-2"
|
||||
>
|
||||
<CheckCircle class="h-4 w-4" />
|
||||
Mark Complete
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue