diff --git a/src/modules/nostr-feed/components/NostrFeed.vue b/src/modules/nostr-feed/components/NostrFeed.vue index 9c431df..b3dfc22 100644 --- a/src/modules/nostr-feed/components/NostrFeed.vue +++ b/src/modules/nostr-feed/components/NostrFeed.vue @@ -99,7 +99,16 @@ const { getDisplayName, fetchProfiles } = useProfiles() const { getEventReactions, subscribeToReactions, toggleLike } = useReactions() // Use scheduled events service -const { getEventsForSpecificDate, getCompletion, toggleComplete, allCompletions } = useScheduledEvents() +const { + getEventsForSpecificDate, + getCompletion, + getTaskStatus, + claimTask, + startTask, + completeEvent, + unclaimTask, + allCompletions +} = useScheduledEvents() // Selected date for viewing scheduled tasks (defaults to today) const selectedDate = ref(new Date().toISOString().split('T')[0]) @@ -255,14 +264,40 @@ async function onToggleLike(note: FeedPost) { } } -// Handle scheduled event completion toggle -async function onToggleComplete(event: ScheduledEvent, occurrence?: string) { - console.log('🎯 NostrFeed: onToggleComplete called for event:', event.title, 'occurrence:', occurrence) +// Task action handlers +async function onClaimTask(event: ScheduledEvent, occurrence?: string) { + console.log('👋 NostrFeed: Claiming task:', event.title) try { - await toggleComplete(event, occurrence) - console.log('✅ NostrFeed: toggleComplete succeeded') + await claimTask(event, '', occurrence) } catch (error) { - console.error('❌ NostrFeed: Failed to toggle event completion:', 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) } } @@ -514,8 +549,12 @@ function cancelDelete() { :event="event" :get-display-name="getDisplayName" :get-completion="getCompletion" + :get-task-status="getTaskStatus" :admin-pubkeys="adminPubkeys" - @toggle-complete="onToggleComplete" + @claim-task="onClaimTask" + @start-task="onStartTask" + @complete-task="onCompleteTask" + @unclaim-task="onUnclaimTask" />
diff --git a/src/modules/nostr-feed/components/ScheduledEventCard.vue b/src/modules/nostr-feed/components/ScheduledEventCard.vue index dfc48af..d6e4ef1 100644 --- a/src/modules/nostr-feed/components/ScheduledEventCard.vue +++ b/src/modules/nostr-feed/components/ScheduledEventCard.vue @@ -15,18 +15,22 @@ import { CollapsibleContent, CollapsibleTrigger, } from '@/components/ui/collapsible' -import { Calendar, MapPin, Clock, CheckCircle } from 'lucide-vue-next' -import type { ScheduledEvent, EventCompletion } from '../services/ScheduledEventService' +import { Calendar, MapPin, Clock, CheckCircle, PlayCircle, Hand } from 'lucide-vue-next' +import type { ScheduledEvent, EventCompletion, TaskStatus } 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: 'toggle-complete', event: ScheduledEvent, occurrence?: string): void + (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 } const props = withDefaults(defineProps(), { @@ -53,12 +57,29 @@ const occurrence = computed(() => { // Check if this is an admin event const isAdminEvent = computed(() => props.adminPubkeys.includes(props.event.pubkey)) -// Check if event is completed - call function with occurrence for recurring events -const isCompleted = computed(() => props.getCompletion(eventAddress.value, occurrence.value)?.completed || false) +// Get current task status +const taskStatus = computed(() => props.getTaskStatus(eventAddress.value, occurrence.value)) // 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)) + +// 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 { @@ -110,28 +131,102 @@ const formattedTimeRange = computed(() => { } }) -// Handle mark complete button click - show confirmation dialog -function handleMarkComplete() { - console.log('🔘 Mark Complete button clicked for event:', props.event.title) +// Action type for confirmation dialog +const pendingAction = ref<'claim' | 'start' | 'complete' | 'unclaim' | null>(null) + +// Handle claim task +function handleClaimTask() { + pendingAction.value = 'claim' showConfirmDialog.value = true } -// 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 +// Handle start task +function handleStartTask() { + pendingAction.value = 'start' + showConfirmDialog.value = true } -// Cancel mark complete -function cancelMarkComplete() { - showConfirmDialog.value = false +// Handle complete task +function handleCompleteTask() { + pendingAction.value = 'complete' + showConfirmDialog.value = true } + +// Handle unclaim task +function handleUnclaimTask() { + pendingAction.value = 'unclaim' + showConfirmDialog.value = true +} + +// Confirm action +function confirmAction() { + if (!pendingAction.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 + } + + showConfirmDialog.value = false + pendingAction.value = null +} + +// Cancel action +function cancelAction() { + showConfirmDialog.value = false + pendingAction.value = null +} + +// 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.`, + confirmText: 'Unclaim Task' + } + default: + return { + title: '', + description: '', + confirmText: '' + } + } +})