From 42bff96c584588e6592b07981c12d7eda12ae28b Mon Sep 17 00:00:00 2001 From: Padreug Date: Thu, 11 Jun 2026 00:11:37 +0200 Subject: [PATCH] feat(activities): show organizer on event cards + route through ProfileService MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two changes that ship together: - Compact variant of OrganizerCard (tiny avatar + display name on a single line) used on every feed EventCard so viewers see who's hosting before they tap into the detail page. Hidden on compact feed rows (host's own roster — they already know). - Refactor useOrganizerProfile.ts to route through the centralized ProfileService. Two bugs the local impl was carrying: * `displayName` was exposed via a `get` accessor on the returned object; destructuring it (`const { displayName } = …`) resolved once at the destructure site, so a kind-0 arriving later never updated the bound name. Now exposed as `computed`. * `relayHub.subscribe()` throws synchronously when the hub isn't connected yet. OrganizerCard mounted during cold start swallowed the throw silently in onMounted, leaving the user with the pubkey-truncated fallback forever. ProfileService.getProfile() awaits the relay-hub connection before issuing the filter. Bonus: ProfileService's kind-0 cache is shared with chat / market / nostr-feed, so a profile fetched by any module is immediately visible to all of them. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/modules/events/components/EventCard.vue | 10 ++ .../events/components/OrganizerCard.vue | 34 +++- .../events/composables/useOrganizerProfile.ts | 156 +++++++----------- 3 files changed, 95 insertions(+), 105 deletions(-) diff --git a/src/modules/events/components/EventCard.vue b/src/modules/events/components/EventCard.vue index b26976d..91ccb0b 100644 --- a/src/modules/events/components/EventCard.vue +++ b/src/modules/events/components/EventCard.vue @@ -6,6 +6,7 @@ import { Card, CardContent } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { MapPin, Calendar, Ticket, User, CheckCircle2, History } from 'lucide-vue-next' import BookmarkButton from './BookmarkButton.vue' +import OrganizerCard from './OrganizerCard.vue' import { useDateLocale } from '../composables/useDateLocale' import { useOwnedTickets } from '../composables/useOwnedTickets' import type { Event } from '../types/event' @@ -208,6 +209,15 @@ const isNonApproved = computed(

+ + +
diff --git a/src/modules/events/components/OrganizerCard.vue b/src/modules/events/components/OrganizerCard.vue index 66030ea..dea6c4f 100644 --- a/src/modules/events/components/OrganizerCard.vue +++ b/src/modules/events/components/OrganizerCard.vue @@ -3,15 +3,37 @@ import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar' import { User } from 'lucide-vue-next' import { useOrganizerProfile } from '../composables/useOrganizerProfile' -const props = defineProps<{ - pubkey: string -}>() +const props = withDefaults( + defineProps<{ + pubkey: string + /** Compact row variant — small avatar, single-line "By ". + * Used on the events feed card where the organizer is a hint, not + * the focus. Default (full) is used on the detail page. */ + compact?: boolean + }>(), + { compact: false }, +) const { profile, displayName, isLoading } = useOrganizerProfile(props.pubkey)