Replaces custom expand/collapse with Collapsible

Migrates ScheduledEventCard to use the Collapsible component from the UI library.

This simplifies the component's structure and improves accessibility by leveraging the built-in features of the Collapsible component.
Removes custom logic for managing the expanded/collapsed state.
This commit is contained in:
padreug 2025-10-21 23:14:56 +02:00
parent abaf7f2f5b
commit 9aa8c28bef

View file

@ -10,6 +10,11 @@ import {
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from '@/components/ui/dialog' } from '@/components/ui/dialog'
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from '@/components/ui/collapsible'
import { Calendar, MapPin, Clock, CheckCircle } from 'lucide-vue-next' import { Calendar, MapPin, Clock, CheckCircle } from 'lucide-vue-next'
import type { ScheduledEvent, EventCompletion } from '../services/ScheduledEventService' import type { ScheduledEvent, EventCompletion } from '../services/ScheduledEventService'
@ -33,9 +38,6 @@ const emit = defineEmits<Emits>()
// Confirmation dialog state // Confirmation dialog state
const showConfirmDialog = ref(false) const showConfirmDialog = ref(false)
// Collapsed state (collapsed by default)
const isExpanded = ref(false)
// Event address for tracking completion // Event address for tracking completion
const eventAddress = computed(() => `31922:${props.event.pubkey}:${props.event.dTag}`) const eventAddress = computed(() => `31922:${props.event.pubkey}:${props.event.dTag}`)
@ -116,81 +118,56 @@ function confirmMarkComplete() {
function cancelMarkComplete() { function cancelMarkComplete() {
showConfirmDialog.value = false showConfirmDialog.value = false
} }
// Toggle expanded/collapsed state
function toggleExpanded() {
isExpanded.value = !isExpanded.value
}
</script> </script>
<template> <template>
<div class="border-b md:border md:rounded-lg bg-card transition-all" <Collapsible class="border-b md:border md:rounded-lg bg-card transition-all"
:class="{ 'opacity-60': isCompletable && isCompleted }"> :class="{ 'opacity-60': isCompletable && isCompleted }">
<!-- Collapsed View (Trigger) -->
<!-- Collapsed View (Default) --> <CollapsibleTrigger as-child>
<div v-if="!isExpanded" <div class="flex items-center gap-3 p-3 md:p-4 cursor-pointer hover:bg-accent/50 transition-colors">
class="flex items-center gap-3 p-3 md:p-4"> <!-- Time -->
<!-- Time --> <div class="flex items-center gap-1.5 text-sm text-muted-foreground shrink-0">
<div @click="toggleExpanded" class="flex items-center gap-1.5 text-sm text-muted-foreground shrink-0 cursor-pointer"> <Clock class="h-3.5 w-3.5" />
<Clock class="h-3.5 w-3.5" /> <span class="font-medium">{{ formattedTimeRange || formattedDate }}</span>
<span class="font-medium">{{ formattedTimeRange || formattedDate }}</span>
</div>
<!-- Title -->
<h3 @click="toggleExpanded"
class="font-semibold text-sm md:text-base flex-1 truncate cursor-pointer hover:text-foreground/80 transition-colors"
:class="{ 'line-through': isCompletable && isCompleted }">
{{ event.title }}
</h3>
<!-- Badges and Actions -->
<div class="flex items-center gap-2 shrink-0">
<!-- Mark Complete Button (for uncompleted tasks) -->
<Button
v-if="isCompletable && !isCompleted"
@click.stop="handleMarkComplete"
variant="ghost"
size="sm"
class="h-7 w-7 p-0"
>
<CheckCircle class="h-4 w-4" />
</Button>
<!-- Completed Badge -->
<Badge v-if="isCompletable && isCompleted" variant="secondary" class="text-xs">
</Badge>
<!-- Admin Badge -->
<Badge v-if="isAdminEvent" variant="secondary" class="text-xs">
Admin
</Badge>
</div>
</div>
<!-- Expanded View -->
<div v-else class="p-4 md:p-6">
<!-- Event Details -->
<div class="flex-1 min-w-0">
<!-- Title and badges with close button -->
<div class="flex items-start gap-2 mb-2 flex-wrap">
<h3 class="font-semibold text-base md:text-lg flex-1"
:class="{ 'line-through': isCompletable && isCompleted }">
{{ event.title }}
</h3>
<Badge v-if="isAdminEvent" variant="secondary" class="shrink-0">
Admin
</Badge>
<Button
@click="toggleExpanded"
variant="ghost"
size="sm"
class="h-6 w-6 p-0 shrink-0"
>
</Button>
</div> </div>
<!-- Title -->
<h3 class="font-semibold text-sm md:text-base flex-1 truncate"
:class="{ 'line-through': isCompletable && isCompleted }">
{{ event.title }}
</h3>
<!-- Badges and Actions -->
<div class="flex items-center gap-2 shrink-0">
<!-- Mark Complete Button (for uncompleted tasks) -->
<Button
v-if="isCompletable && !isCompleted"
@click.stop="handleMarkComplete"
variant="ghost"
size="sm"
class="h-7 w-7 p-0"
>
<CheckCircle class="h-4 w-4" />
</Button>
<!-- Completed Badge -->
<Badge v-if="isCompletable && isCompleted" variant="secondary" class="text-xs">
</Badge>
<!-- Admin Badge -->
<Badge v-if="isAdminEvent" variant="secondary" class="text-xs">
Admin
</Badge>
</div>
</div>
</CollapsibleTrigger>
<!-- Expanded View (Content) -->
<CollapsibleContent class="p-4 md:p-6 pt-0">
<!-- Event Details -->
<div class="flex-1 min-w-0">
<!-- Date/Time --> <!-- Date/Time -->
<div class="flex items-center gap-4 text-sm text-muted-foreground mb-2 flex-wrap"> <div class="flex items-center gap-4 text-sm text-muted-foreground mb-2 flex-wrap">
<div class="flex items-center gap-1.5"> <div class="flex items-center gap-1.5">
@ -238,22 +215,23 @@ function toggleExpanded() {
</Button> </Button>
</div> </div>
</div> </div>
</div> </CollapsibleContent>
<!-- Confirmation Dialog --> </Collapsible>
<Dialog :open="showConfirmDialog" @update:open="(val: boolean) => showConfirmDialog = val">
<DialogContent> <!-- Confirmation Dialog -->
<DialogHeader> <Dialog :open="showConfirmDialog" @update:open="(val: boolean) => showConfirmDialog = val">
<DialogTitle>Mark Event as Complete?</DialogTitle> <DialogContent>
<DialogDescription> <DialogHeader>
This will mark "{{ event.title }}" as completed by you. Other users will be able to see that you completed this event. <DialogTitle>Mark Event as Complete?</DialogTitle>
</DialogDescription> <DialogDescription>
</DialogHeader> This will mark "{{ event.title }}" as completed by you. Other users will be able to see that you completed this event.
<DialogFooter> </DialogDescription>
<Button variant="outline" @click="cancelMarkComplete">Cancel</Button> </DialogHeader>
<Button @click="confirmMarkComplete">Mark Complete</Button> <DialogFooter>
</DialogFooter> <Button variant="outline" @click="cancelMarkComplete">Cancel</Button>
</DialogContent> <Button @click="confirmMarkComplete">Mark Complete</Button>
</Dialog> </DialogFooter>
</div> </DialogContent>
</Dialog>
</template> </template>