diff --git a/src/activities-app/App.vue b/src/activities-app/App.vue index 640608b..dc3ada6 100644 --- a/src/activities-app/App.vue +++ b/src/activities-app/App.vue @@ -7,7 +7,6 @@ import AppShell from '@/components/layout/AppShell.vue' import type { BottomTab } from '@/components/layout/BottomNav.vue' import { useAuth } from '@/composables/useAuthService' import { useActivitiesStore } from '@/modules/activities/stores/activities' -import { useActivities } from '@/modules/activities/composables/useActivities' import { useApprovalState } from '@/modules/activities/composables/useApprovalState' import { injectService, SERVICE_TOKENS } from '@/core/di-container' import type { TicketApiService } from '@/modules/activities/services/TicketApiService' @@ -19,10 +18,6 @@ const { t } = useI18n() const { isAuthenticated, currentUser } = useAuth() const activitiesStore = useActivitiesStore() const { isAdmin, autoApprove } = useApprovalState() -// Used to merge own LNbits drafts into the activities feed right after -// the user creates or edits an event — otherwise the new draft only -// surfaces on the next ActivitiesPage subscribe cycle. -const { loadOwnEvents } = useActivities() // Settings dropped — theme/lang/currency now live in the shared profile sheet. // Create lives in the bottom nav (auth-gated): activity creation is a deliberate @@ -101,8 +96,6 @@ function handleDialogOpenChange(open: boolean) { :on-create-event="handleCreateEvent" :on-update-event="handleUpdateEvent" @update:open="handleDialogOpenChange" - @event-created="loadOwnEvents" - @event-updated="loadOwnEvents" /> diff --git a/src/modules/activities/components/ActivityCard.vue b/src/modules/activities/components/ActivityCard.vue index d021b10..71054fb 100644 --- a/src/modules/activities/components/ActivityCard.vue +++ b/src/modules/activities/components/ActivityCard.vue @@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n' import { format } from 'date-fns' import { Card, CardContent } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' -import { MapPin, Calendar, Ticket, User } from 'lucide-vue-next' +import { MapPin, Calendar, Ticket } from 'lucide-vue-next' import BookmarkButton from './BookmarkButton.vue' import { useDateLocale } from '../composables/useDateLocale' import type { Activity } from '../types/activity' @@ -87,17 +87,6 @@ const placeholderBg = computed(() => { {{ categoryLabel }} - - - - Yours - - { {{ priceDisplay }} - - - {{ activity.lnbitsStatus === 'rejected' ? 'Rejected' : 'Pending review' }} - diff --git a/src/modules/activities/components/CreateEventDialog.vue b/src/modules/activities/components/CreateEventDialog.vue index 180184b..a32846a 100644 --- a/src/modules/activities/components/CreateEventDialog.vue +++ b/src/modules/activities/components/CreateEventDialog.vue @@ -67,12 +67,8 @@ const emit = defineEmits<{ }>() const isEditMode = computed(() => Boolean(props.event?.id)) -// True when the submission will land in `proposed` status: a non-admin -// owner with the extension's auto_approve toggle off. Same gate for -// create and edit; the edit path also keys the in-form warning banner -// on this so the user sees the consequence before submitting. -const willLandInPending = computed( - () => !props.isAdmin && !props.autoApprove +const willGoToPending = computed( + () => isEditMode.value && !props.isAdmin && !props.autoApprove ) const { t } = useI18n() @@ -306,8 +302,8 @@ const onSubmit = form.handleSubmit(async (formValues) => { } await props.onUpdateEvent(props.event.id, eventData) toastService.success( - willLandInPending.value - ? 'Updated — awaiting re-approval. Hidden from the public feed until reviewed.' + willGoToPending.value + ? 'Event updated — pending re-approval' : 'Event updated!' ) emit('event-updated') @@ -317,11 +313,7 @@ const onSubmit = form.handleSubmit(async (formValues) => { return } await props.onCreateEvent(eventData) - toastService.success( - willLandInPending.value - ? 'Submitted! Awaiting admin approval — your draft is visible on your feed with a Pending badge.' - : 'Event submitted!' - ) + toastService.success('Event submitted!') emit('event-created') } @@ -371,7 +363,7 @@ const handleOpenChange = (open: boolean) => {
- + Saving will resubmit for approval. The event will be removed diff --git a/src/modules/activities/composables/useActivities.ts b/src/modules/activities/composables/useActivities.ts index 78b1bb5..edc4b02 100644 --- a/src/modules/activities/composables/useActivities.ts +++ b/src/modules/activities/composables/useActivities.ts @@ -1,11 +1,7 @@ import { ref, computed, onUnmounted } from 'vue' import { tryInjectService, SERVICE_TOKENS } from '@/core/di-container' -import { useAuth } from '@/composables/useAuthService' import type { ActivitiesNostrService } from '../services/ActivitiesNostrService' import type { CalendarEventFilters } from '../services/ActivitiesNostrService' -import type { TicketApiService } from '../services/TicketApiService' -import type { TicketedEvent } from '../types/ticket' -import { ticketedEventToActivity } from '../types/activity' import { useActivitiesStore } from '../stores/activities' import { useActivityFilters } from './useActivityFilters' @@ -16,55 +12,11 @@ import { useActivityFilters } from './useActivityFilters' export function useActivities() { const store = useActivitiesStore() const filters = useActivityFilters() - const { isAuthenticated, currentUser } = useAuth() const isSubscribed = ref(false) const subscriptionError = ref(null) let unsubscribe: (() => void) | null = null - /** - * Merge the caller's own LNbits events (any status) into the feed. - * - * The `/activities` feed is Nostr-driven, so an event that hasn't - * been published yet — typically because it's still `proposed` under - * auto_approve=off — would silently vanish from the creator's view - * until an admin approves it. Pull own events from the events - * extension and upsert them as Activities so users see their own - * drafts with a Pending-review badge. - * - * Once an event is approved and the Nostr relay delivers the kind - * 31922/31923 event, the relay-sourced Activity has a newer - * createdAt and wins on upsert (it lacks `lnbitsStatus`, so the - * badge disappears). - */ - /** - * Stamp `isMine` on a Nostr-sourced activity when the organizer - * pubkey matches the logged-in user's Nostr key. LNbits drafts come - * pre-tagged via the adapter. - */ - function tagOwnership(activity: { organizer: { pubkey: string }; isMine?: boolean }) { - const myPubkey = currentUser.value?.pubkey - if (myPubkey && activity.organizer.pubkey === myPubkey) { - activity.isMine = true - } - } - - async function loadOwnEvents() { - if (!isAuthenticated.value) return - const invoiceKey = currentUser.value?.wallets?.[0]?.inkey - if (!invoiceKey) return - const ticketApi = tryInjectService(SERVICE_TOKENS.TICKET_API) - if (!ticketApi) return - try { - const mine = (await ticketApi.fetchMyEvents(invoiceKey)) as TicketedEvent[] - for (const ev of mine) { - store.upsertActivity(ticketedEventToActivity(ev)) - } - } catch (err) { - console.warn('[useActivities] loadOwnEvents failed:', err) - } - } - // Filtered and sorted activities (from all activities, filters handle time range) const filteredActivities = computed(() => { const all = store.activities.sort( @@ -91,7 +43,6 @@ export function useActivities() { unsubscribe = nostrService.subscribeToCalendarEvents( (activity) => { - tagOwnership(activity) store.upsertActivity(activity) store.isLoading = false }, @@ -100,10 +51,6 @@ export function useActivities() { isSubscribed.value = true - // Best-effort merge of own LNbits events (any status) so the - // creator sees their own pending drafts on the feed too. - loadOwnEvents() - // Set loading to false after a timeout (in case no events arrive) setTimeout(() => { store.isLoading = false @@ -128,7 +75,6 @@ export function useActivities() { store.isLoading = true subscriptionError.value = null const activities = await nostrService.queryCalendarEvents(eventFilters) - for (const a of activities) tagOwnership(a) store.upsertActivities(activities) } catch (err) { subscriptionError.value = err instanceof Error ? err.message : 'Failed to query activities' @@ -179,6 +125,5 @@ export function useActivities() { query, stop, refresh, - loadOwnEvents, } } diff --git a/src/modules/activities/types/activity.ts b/src/modules/activities/types/activity.ts index a377e8b..24543a0 100644 --- a/src/modules/activities/types/activity.ts +++ b/src/modules/activities/types/activity.ts @@ -1,7 +1,6 @@ import ngeohash from 'ngeohash' import type { ActivityCategory } from './category' import type { CalendarTimeEvent, CalendarDateEvent } from './nip52' -import type { TicketedEvent } from './ticket' /** * Unified view model for displaying activities in the UI. @@ -46,22 +45,6 @@ export interface Activity { isPrivate: boolean /** Nostr event created_at timestamp */ createdAt: Date - /** - * LNbits approval status, when the activity came from the events - * extension rather than a Nostr relay. Undefined for activities - * sourced from Nostr (approved by definition — only published - * events make it onto relays). Used to render a "Pending review" - * badge for the creator's own non-approved drafts. - */ - lnbitsStatus?: 'approved' | 'proposed' | 'rejected' - /** - * Belongs to the current user. Set by the adapter for own LNbits - * drafts and by the activities-subscribe callback when the Nostr - * organizer pubkey matches the logged-in user. Used to render a - * "Yours" badge on the feed so the creator can spot their events - * at a glance. - */ - isMine?: boolean } export interface OrganizerInfo { @@ -145,74 +128,6 @@ export function calendarDateEventToActivity(event: CalendarDateEvent, organizer? } } -/** - * Convert an LNbits TicketedEvent to an Activity view model. - * - * Used to surface the caller's own pending events on the activities - * feed alongside Nostr-published activities. Once an event is approved - * and published, the Nostr-derived Activity (newer createdAt) wins on - * upsert in the activities store and this draft version is replaced. - * - * The wire format for dates mirrors how nostr_publisher emits NIP-52: - * - "YYYY-MM-DD" → date-based (kind 31922 on publish) - * - "YYYY-MM-DDTHH:MM..." → time-based (kind 31923 on publish) - */ -export function ticketedEventToActivity( - event: TicketedEvent, - organizer?: Partial, -): Activity { - const hasTime = event.event_start_date.includes('T') - const startDate = hasTime - ? new Date(event.event_start_date) - : parseDateOnly(event.event_start_date) - const endRaw = event.event_end_date - const endDate = endRaw - ? endRaw.includes('T') - ? new Date(endRaw) - : parseDateOnly(endRaw) - : undefined - - const category = event.categories?.[0] as ActivityCategory | undefined - - return { - id: event.id, - // No published Nostr event yet for pending drafts; reuse the LNbits - // id as a placeholder. Approved + published versions will overwrite - // this with the real Nostr event id. - nostrEventId: event.id, - type: hasTime ? 'time' : 'date', - organizer: { - // Pending events have no Nostr pubkey yet. Empty string is fine - // — the card layer falls back gracefully and the OrganizerCard - // is only shown for approved (Nostr-sourced) activities anyway. - pubkey: '', - ...organizer, - }, - title: event.name, - description: event.info ?? '', - image: event.banner ?? undefined, - startDate, - endDate, - location: event.location ?? undefined, - category, - tags: event.categories ?? [], - isPrivate: false, - // event.time is the LNbits creation timestamp (ISO string after - // FastAPI serialization). new Date() handles both ISO strings and - // numeric epoch — same shape used in useEvents sorting. - createdAt: new Date(event.time) || new Date(), - lnbitsStatus: event.status as Activity['lnbitsStatus'], - // fetchMyEvents only returns the caller's own events, so anything - // reaching this adapter is by definition mine. - isMine: true, - } -} - -function parseDateOnly(dateStr: string): Date { - const [year, month, day] = dateStr.split('-').map(Number) - return new Date(Date.UTC(year, month - 1, day)) -} - function decodeGeohash(geohash?: string): { lat: number; lng: number } | undefined { if (!geohash) return undefined try { diff --git a/src/modules/activities/views/ActivityDetailPage.vue b/src/modules/activities/views/ActivityDetailPage.vue index 1929ca2..9c509b7 100644 --- a/src/modules/activities/views/ActivityDetailPage.vue +++ b/src/modules/activities/views/ActivityDetailPage.vue @@ -156,20 +156,6 @@ function goBack() { {{ categoryLabel }} - - {{ activity.lnbitsStatus === 'rejected' ? 'Rejected' : 'Pending review' }} - - - Yours -
{{ tag }}