Adds support for completable task events

Enables marking scheduled events as complete based on a new "event-type" tag.

This change introduces the concept of "completable" events, specifically for events of type "task". It modifies the ScheduledEventCard component to:

- Display completion information only for completable events
- Show the "Mark Complete" button only for completable events that are not yet completed
- Adjust the opacity and strikethrough styling based on the event's completable and completed status.

The ScheduledEventService is updated to extract the event type from the "event-type" tag.
This commit is contained in:
padreug 2025-10-21 22:53:08 +02:00
parent 46418ef6fd
commit 661b700092
2 changed files with 12 additions and 6 deletions

View file

@ -42,6 +42,9 @@ const isAdminEvent = computed(() => props.adminPubkeys.includes(props.event.pubk
// Check if event is completed - call function directly // Check if event is completed - call function directly
const isCompleted = computed(() => props.getCompletion(eventAddress.value)?.completed || false) const isCompleted = computed(() => props.getCompletion(eventAddress.value)?.completed || false)
// Check if event is completable (task type)
const isCompletable = computed(() => props.event.eventType === 'task')
// Format the date/time // Format the date/time
const formattedDate = computed(() => { const formattedDate = computed(() => {
try { try {
@ -114,13 +117,13 @@ function cancelMarkComplete() {
<template> <template>
<div class="border-b md:border md:rounded-lg bg-card p-4 md:p-6 transition-all" <div class="border-b md:border md:rounded-lg bg-card p-4 md:p-6 transition-all"
:class="{ 'opacity-60': isCompleted }"> :class="{ 'opacity-60': isCompletable && isCompleted }">
<!-- Event Details --> <!-- Event Details -->
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
<!-- Title and badges --> <!-- Title and badges -->
<div class="flex items-start gap-2 mb-2 flex-wrap"> <div class="flex items-start gap-2 mb-2 flex-wrap">
<h3 class="font-semibold text-base md:text-lg flex-1" <h3 class="font-semibold text-base md:text-lg flex-1"
:class="{ 'line-through': isCompleted }"> :class="{ 'line-through': isCompletable && isCompleted }">
{{ event.title }} {{ event.title }}
</h3> </h3>
<Badge v-if="isAdminEvent" variant="secondary" class="shrink-0"> <Badge v-if="isAdminEvent" variant="secondary" class="shrink-0">
@ -151,8 +154,8 @@ function cancelMarkComplete() {
<p class="whitespace-pre-wrap break-words">{{ event.description || event.content }}</p> <p class="whitespace-pre-wrap break-words">{{ event.description || event.content }}</p>
</div> </div>
<!-- Completion info --> <!-- Completion info (only for completable events) -->
<div v-if="isCompleted && getCompletion(eventAddress)" class="text-xs text-muted-foreground mb-3"> <div v-if="isCompletable && isCompleted && getCompletion(eventAddress)" class="text-xs text-muted-foreground mb-3">
Completed by {{ getDisplayName(getCompletion(eventAddress)!.pubkey) }} Completed by {{ getDisplayName(getCompletion(eventAddress)!.pubkey) }}
<span v-if="getCompletion(eventAddress)!.notes"> - {{ getCompletion(eventAddress)!.notes }}</span> <span v-if="getCompletion(eventAddress)!.notes"> - {{ getCompletion(eventAddress)!.notes }}</span>
</div> </div>
@ -162,8 +165,8 @@ function cancelMarkComplete() {
Posted by {{ getDisplayName(event.pubkey) }} Posted by {{ getDisplayName(event.pubkey) }}
</div> </div>
<!-- Mark Complete Button --> <!-- Mark Complete Button (only for completable task events) -->
<div v-if="!isCompleted" class="mt-3"> <div v-if="isCompletable && !isCompleted" class="mt-3">
<Button <Button
@click="handleMarkComplete" @click="handleMarkComplete"
variant="outline" variant="outline"

View file

@ -15,6 +15,7 @@ export interface ScheduledEvent {
description?: string description?: string
location?: string location?: string
status: string status: string
eventType?: string // 'task' for completable events, 'announcement' for informational
content: string content: string
tags: string[][] tags: string[][]
} }
@ -76,6 +77,7 @@ export class ScheduledEventService extends BaseService {
const description = event.tags.find(tag => tag[0] === 'description')?.[1] const description = event.tags.find(tag => tag[0] === 'description')?.[1]
const location = event.tags.find(tag => tag[0] === 'location')?.[1] const location = event.tags.find(tag => tag[0] === 'location')?.[1]
const status = event.tags.find(tag => tag[0] === 'status')?.[1] || 'pending' const status = event.tags.find(tag => tag[0] === 'status')?.[1] || 'pending'
const eventType = event.tags.find(tag => tag[0] === 'event-type')?.[1]
if (!start) { if (!start) {
console.warn('Scheduled event missing start date:', event.id) console.warn('Scheduled event missing start date:', event.id)
@ -96,6 +98,7 @@ export class ScheduledEventService extends BaseService {
description, description,
location, location,
status, status,
eventType,
content: event.content, content: event.content,
tags: event.tags tags: event.tags
} }