Fix unclaim permission bug - only show button for task owner

Previously, users could see and click "Unclaim" button for tasks claimed by others, leading to failed deletion attempts and temporary UI inconsistencies.

Changes:
- Add auth service injection to ScheduledEventCard
- Add canUnclaim computed property checking if current user created the current status
- Only show "Unclaim" button when canUnclaim is true (user owns the current status)
- Applies NIP-09 rule: users can only delete their own events

Behavior:
- Alice claims task → only Alice sees "Unclaim" button
- Bob marks task in-progress → only Bob sees "Unclaim" button
- Prevents failed deletion attempts and optimistic update bugs
- Follows Nostr protocol permissions correctly

This is a quick fix. Future enhancement will track per-user status for full collaborative workflow support.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
padreug 2025-11-16 20:54:25 +01:00
parent 76fbf7579f
commit d0b3396af7

View file

@ -17,6 +17,8 @@ import {
} from '@/components/ui/collapsible'
import { Calendar, MapPin, Clock, CheckCircle, PlayCircle, Hand } 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'
interface Props {
event: ScheduledEvent
@ -39,6 +41,9 @@ const props = withDefaults(defineProps<Props>(), {
const emit = defineEmits<Emits>()
// Get auth service to check current user
const authService = injectService<AuthService>(SERVICE_TOKENS.AUTH_SERVICE)
// Confirmation dialog state
const showConfirmDialog = ref(false)
@ -66,6 +71,15 @@ 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 if they created the current status)
const canUnclaim = computed(() => {
if (!completion.value || !currentUserPubkey.value) return false
return completion.value.pubkey === currentUserPubkey.value
})
// Status badges configuration
const statusConfig = computed(() => {
switch (taskStatus.value) {
@ -394,6 +408,7 @@ const dialogContent = computed(() => {
Mark Complete
</Button>
<Button
v-if="canUnclaim"
@click.stop="handleUnclaimTask"
variant="outline"
size="sm"
@ -414,6 +429,7 @@ const dialogContent = computed(() => {
Mark Complete
</Button>
<Button
v-if="canUnclaim"
@click.stop="handleUnclaimTask"
variant="outline"
size="sm"
@ -425,6 +441,7 @@ const dialogContent = computed(() => {
<!-- Completed Task -->
<template v-else-if="taskStatus === 'completed'">
<Button
v-if="canUnclaim"
@click.stop="handleUnclaimTask"
variant="outline"
size="sm"