diff --git a/src/app.config.ts b/src/app.config.ts index e461872..8893996 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -64,7 +64,7 @@ export const appConfig: AppConfig = { }, events: { name: 'events', - enabled: false, + enabled: true, lazy: false, config: { apiConfig: { diff --git a/src/modules/base/nostr/relay-hub.ts b/src/modules/base/nostr/relay-hub.ts index 7cdd00f..486d3f2 100644 --- a/src/modules/base/nostr/relay-hub.ts +++ b/src/modules/base/nostr/relay-hub.ts @@ -540,12 +540,8 @@ export class RelayHub extends BaseService { const successful = results.filter(result => result.status === 'fulfilled').length const total = results.length - this.emit('eventPublished', { eventId: event.id, success: successful, total }) - // Throw error if no relays accepted the event - if (successful === 0) { - throw new Error(`Failed to publish event - none of the ${total} relay(s) accepted it`) - } + this.emit('eventPublished', { eventId: event.id, success: successful, total }) return { success: successful, total } } diff --git a/src/modules/nostr-feed/components/NostrFeed.vue b/src/modules/nostr-feed/components/NostrFeed.vue index 529b7d7..2d0aa4c 100644 --- a/src/modules/nostr-feed/components/NostrFeed.vue +++ b/src/modules/nostr-feed/components/NostrFeed.vue @@ -99,22 +99,12 @@ const { getDisplayName, fetchProfiles } = useProfiles() const { getEventReactions, subscribeToReactions, toggleLike } = useReactions() // Use scheduled events service -const { - getEventsForSpecificDate, - getCompletion, - getTaskStatus, - claimTask, - startTask, - completeEvent, - unclaimTask, - deleteTask, - allCompletions -} = useScheduledEvents() +const { getEventsForSpecificDate, getCompletion, toggleComplete, allCompletions } = useScheduledEvents() -// Selected date for viewing scheduled tasks (defaults to today) +// Selected date for viewing events (defaults to today) const selectedDate = ref(new Date().toISOString().split('T')[0]) -// Get scheduled tasks for the selected date (reactive) +// Get scheduled events for the selected date (reactive) const scheduledEventsForDate = computed(() => getEventsForSpecificDate(selectedDate.value)) // Navigate to previous day @@ -153,20 +143,20 @@ const dateDisplayText = computed(() => { const tomorrowStr = tomorrow.toISOString().split('T')[0] if (selectedDate.value === today) { - return "Today's Tasks" + return "Today's Events" } else if (selectedDate.value === yesterdayStr) { - return "Yesterday's Tasks" + return "Yesterday's Events" } else if (selectedDate.value === tomorrowStr) { - return "Tomorrow's Tasks" + return "Tomorrow's Events" } else { - // Format as "Tasks for Mon, Jan 15" + // Format as "Events for Mon, Jan 15" const date = new Date(selectedDate.value + 'T00:00:00') const formatted = date.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric' }) - return `Tasks for ${formatted}` + return `Events for ${formatted}` } }) @@ -265,49 +255,14 @@ async function onToggleLike(note: FeedPost) { } } -// Task action handlers -async function onClaimTask(event: ScheduledEvent, occurrence?: string) { - console.log('👋 NostrFeed: Claiming task:', event.title) +// Handle scheduled event completion toggle +async function onToggleComplete(event: ScheduledEvent, occurrence?: string) { + console.log('🎯 NostrFeed: onToggleComplete called for event:', event.title, 'occurrence:', occurrence) try { - await claimTask(event, '', occurrence) + await toggleComplete(event, occurrence) + console.log('✅ NostrFeed: toggleComplete succeeded') } catch (error) { - console.error('❌ Failed to claim task:', error) - } -} - -async function onStartTask(event: ScheduledEvent, occurrence?: string) { - console.log('▶️ NostrFeed: Starting task:', event.title) - try { - await startTask(event, '', occurrence) - } catch (error) { - console.error('❌ Failed to start task:', error) - } -} - -async function onCompleteTask(event: ScheduledEvent, occurrence?: string) { - console.log('✅ NostrFeed: Completing task:', event.title) - try { - await completeEvent(event, occurrence, '') - } catch (error) { - console.error('❌ Failed to complete task:', error) - } -} - -async function onUnclaimTask(event: ScheduledEvent, occurrence?: string) { - console.log('🔙 NostrFeed: Unclaiming task:', event.title) - try { - await unclaimTask(event, occurrence) - } catch (error) { - console.error('❌ Failed to unclaim task:', error) - } -} - -async function onDeleteTask(event: ScheduledEvent) { - console.log('🗑️ NostrFeed: Deleting task:', event.title) - try { - await deleteTask(event) - } catch (error) { - console.error('❌ Failed to delete task:', error) + console.error('❌ NostrFeed: Failed to toggle event completion:', error) } } @@ -511,7 +466,7 @@ function cancelDelete() {
- +
@@ -551,7 +506,7 @@ function cancelDelete() {
- +
diff --git a/src/modules/nostr-feed/components/ScheduledEventCard.vue b/src/modules/nostr-feed/components/ScheduledEventCard.vue index 46c188e..dfc48af 100644 --- a/src/modules/nostr-feed/components/ScheduledEventCard.vue +++ b/src/modules/nostr-feed/components/ScheduledEventCard.vue @@ -2,7 +2,6 @@ import { computed, ref } from 'vue' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' -import { Checkbox } from '@/components/ui/checkbox' import { Dialog, DialogContent, @@ -16,25 +15,18 @@ import { CollapsibleContent, CollapsibleTrigger, } from '@/components/ui/collapsible' -import { Calendar, MapPin, Clock, CheckCircle, PlayCircle, Hand, Trash2 } from 'lucide-vue-next' -import type { ScheduledEvent, EventCompletion, TaskStatus } from '../services/ScheduledEventService' -import { injectService, SERVICE_TOKENS } from '@/core/di-container' -import type { AuthService } from '@/modules/base/auth/auth-service' +import { Calendar, MapPin, Clock, CheckCircle } from 'lucide-vue-next' +import type { ScheduledEvent, EventCompletion } from '../services/ScheduledEventService' interface Props { event: ScheduledEvent getDisplayName: (pubkey: string) => string getCompletion: (eventAddress: string, occurrence?: string) => EventCompletion | undefined - getTaskStatus: (eventAddress: string, occurrence?: string) => TaskStatus | null adminPubkeys?: string[] } interface Emits { - (e: 'claim-task', event: ScheduledEvent, occurrence?: string): void - (e: 'start-task', event: ScheduledEvent, occurrence?: string): void - (e: 'complete-task', event: ScheduledEvent, occurrence?: string): void - (e: 'unclaim-task', event: ScheduledEvent, occurrence?: string): void - (e: 'delete-task', event: ScheduledEvent): void + (e: 'toggle-complete', event: ScheduledEvent, occurrence?: string): void } const props = withDefaults(defineProps(), { @@ -43,12 +35,8 @@ const props = withDefaults(defineProps(), { const emit = defineEmits() -// Get auth service to check current user -const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE) - // Confirmation dialog state const showConfirmDialog = ref(false) -const hasConfirmedCommunication = ref(false) // Event address for tracking completion const eventAddress = computed(() => `31922:${props.event.pubkey}:${props.event.dTag}`) @@ -65,46 +53,12 @@ const occurrence = computed(() => { // Check if this is an admin event const isAdminEvent = computed(() => props.adminPubkeys.includes(props.event.pubkey)) -// Get current task status -const taskStatus = computed(() => props.getTaskStatus(eventAddress.value, occurrence.value)) +// 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') -// Get completion data -const completion = computed(() => props.getCompletion(eventAddress.value, occurrence.value)) - -// Get current user's pubkey -const currentUserPubkey = computed(() => authService?.user.value?.pubkey) - -// Check if current user can unclaim -// Only show unclaim for "claimed" state, and only if current user is the one who claimed it -const canUnclaim = computed(() => { - if (!completion.value || !currentUserPubkey.value) return false - if (taskStatus.value !== 'claimed') return false - return completion.value.pubkey === currentUserPubkey.value -}) - -// Check if current user is the author of the task -const isAuthor = computed(() => { - if (!currentUserPubkey.value) return false - return props.event.pubkey === currentUserPubkey.value -}) - -// Status badges configuration -const statusConfig = computed(() => { - switch (taskStatus.value) { - case 'claimed': - return { label: 'Claimed', variant: 'secondary' as const, icon: Hand, color: 'text-blue-600' } - case 'in-progress': - return { label: 'In Progress', variant: 'default' as const, icon: PlayCircle, color: 'text-orange-600' } - case 'completed': - return { label: 'Completed', variant: 'secondary' as const, icon: CheckCircle, color: 'text-green-600' } - default: - return null - } -}) - // Format the date/time const formattedDate = computed(() => { try { @@ -156,124 +110,28 @@ const formattedTimeRange = computed(() => { } }) -// Action type for confirmation dialog -const pendingAction = ref<'claim' | 'start' | 'complete' | 'unclaim' | 'delete' | null>(null) - -// Handle claim task -function handleClaimTask() { - pendingAction.value = 'claim' +// Handle mark complete button click - show confirmation dialog +function handleMarkComplete() { + console.log('🔘 Mark Complete button clicked for event:', props.event.title) showConfirmDialog.value = true } -// Handle start task -function handleStartTask() { - pendingAction.value = 'start' - showConfirmDialog.value = true -} - -// Handle complete task -function handleCompleteTask() { - pendingAction.value = 'complete' - showConfirmDialog.value = true -} - -// Handle unclaim task -function handleUnclaimTask() { - pendingAction.value = 'unclaim' - showConfirmDialog.value = true -} - -// Handle delete task -function handleDeleteTask() { - pendingAction.value = 'delete' - showConfirmDialog.value = true -} - -// Confirm action -function confirmAction() { - if (!pendingAction.value) return - - // For unclaim action, require checkbox confirmation - if (pendingAction.value === 'unclaim' && !hasConfirmedCommunication.value) { - return - } - - switch (pendingAction.value) { - case 'claim': - emit('claim-task', props.event, occurrence.value) - break - case 'start': - emit('start-task', props.event, occurrence.value) - break - case 'complete': - emit('complete-task', props.event, occurrence.value) - break - case 'unclaim': - emit('unclaim-task', props.event, occurrence.value) - break - case 'delete': - emit('delete-task', props.event) - break - } - +// Confirm and execute mark complete +function confirmMarkComplete() { + console.log('✅ Confirmed mark complete for event:', props.event.title, 'occurrence:', occurrence.value) + emit('toggle-complete', props.event, occurrence.value) showConfirmDialog.value = false - pendingAction.value = null - hasConfirmedCommunication.value = false } -// Cancel action -function cancelAction() { +// Cancel mark complete +function cancelMarkComplete() { showConfirmDialog.value = false - pendingAction.value = null - hasConfirmedCommunication.value = false } - -// Get dialog content based on pending action -const dialogContent = computed(() => { - switch (pendingAction.value) { - case 'claim': - return { - title: 'Claim Task?', - description: `This will mark "${props.event.title}" as claimed by you. You can start working on it later.`, - confirmText: 'Claim Task' - } - case 'start': - return { - title: 'Start Task?', - description: `This will mark "${props.event.title}" as in-progress. Others will see you're actively working on it.`, - confirmText: 'Start Task' - } - case 'complete': - return { - title: 'Complete Task?', - description: `This will mark "${props.event.title}" as completed by you. Other users will be able to see that you completed this task.`, - confirmText: 'Mark Complete' - } - case 'unclaim': - return { - title: 'Unclaim Task?', - description: `This will remove your claim on "${props.event.title}" and make it available for others.\n\nHave you communicated to others that you are unclaiming this task?`, - confirmText: 'Unclaim Task' - } - case 'delete': - return { - title: 'Delete Task?', - description: `This will permanently delete "${props.event.title}". This action cannot be undone.`, - confirmText: 'Delete Task' - } - default: - return { - title: '', - description: '', - confirmText: '' - } - } -})