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:
parent
76fbf7579f
commit
d0b3396af7
1 changed files with 17 additions and 0 deletions
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue