From 7ab2845d6bcc0db23123e6112ec4eefe8da577aa Mon Sep 17 00:00:00 2001 From: Snepsid <101685992+Snepsid@users.noreply.github.com> Date: Fri, 15 May 2026 14:00:43 -0400 Subject: [PATCH 1/3] fix market route state refresh --- .../phunk-grid/phunk-grid.component.html | 2 +- .../src/app/state/data/data-state.effects.ts | 24 +++++++++++-------- .../app/state/market/market-state.effects.ts | 6 +++++ .../app/state/market/market-state.reducers.ts | 13 +++++++++- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/marketplace/src/app/components/phunk-grid/phunk-grid.component.html b/marketplace/src/app/components/phunk-grid/phunk-grid.component.html index d731cfc2..feb8390c 100644 --- a/marketplace/src/app/components/phunk-grid/phunk-grid.component.html +++ b/marketplace/src/app/components/phunk-grid/phunk-grid.component.html @@ -7,7 +7,7 @@ @if (data) { @for ( phunk of data; - track phunk.sha; + track phunk.event?.txId || phunk.sha; let i = $index; ) { @if (i < limit) { diff --git a/marketplace/src/app/state/data/data-state.effects.ts b/marketplace/src/app/state/data/data-state.effects.ts index 3d8a53c0..9a85f057 100644 --- a/marketplace/src/app/state/data/data-state.effects.ts +++ b/marketplace/src/app/state/data/data-state.effects.ts @@ -13,8 +13,9 @@ import * as dataStateActions from '@/state/data/data-state.actions'; import * as dataStateSelectors from '@/state/data/data-state.selectors'; import * as marketStateSelectors from '@/state/market/market-state.selectors'; +import * as marketStateActions from '@/state/market/market-state.actions'; -import { filter, map, switchMap, take, tap } from 'rxjs'; +import { distinctUntilChanged, filter, map, switchMap, take, withLatestFrom } from 'rxjs'; @Injectable() export class DataStateEffects { @@ -46,15 +47,18 @@ export class DataStateEffects { )); setActiveCollection$ = createEffect(() => this.actions$.pipe( - ofType(dataStateActions.setCollections), - switchMap((action) => { - return this.store.select(marketStateSelectors.selectMarketSlug).pipe( - filter(() => !!action.collections), - map((slug) => action.collections.find((c) => c.slug === slug)), - filter((activeCollection) => !!activeCollection), - map((activeCollection) => dataStateActions.setActiveCollection({ activeCollection: { ...activeCollection! } })) - ); - }), + ofType( + dataStateActions.setCollections, + marketStateActions.setMarketSlug, + ), + withLatestFrom( + this.store.select(dataStateSelectors.selectCollections), + this.store.select(marketStateSelectors.selectMarketSlug), + ), + map(([, collections, slug]) => collections.find((c) => c.slug === slug)), + filter((activeCollection) => !!activeCollection), + distinctUntilChanged((a, b) => a?.slug === b?.slug), + map((activeCollection) => dataStateActions.setActiveCollection({ activeCollection: { ...activeCollection! } })) )); fetchLeaderboard$ = createEffect(() => this.actions$.pipe( diff --git a/marketplace/src/app/state/market/market-state.effects.ts b/marketplace/src/app/state/market/market-state.effects.ts index 81ca40a0..512f901b 100644 --- a/marketplace/src/app/state/market/market-state.effects.ts +++ b/marketplace/src/app/state/market/market-state.effects.ts @@ -160,6 +160,12 @@ export class MarketStateEffects { map((events) => dataStateActions.setEvents({ events })), )); + clearEventsOnMarketSlugChange$ = createEffect(() => this.actions$.pipe( + ofType(marketStateActions.setMarketSlug), + distinctUntilChanged((a, b) => a.marketSlug === b.marketSlug), + map(() => dataStateActions.setEvents({ events: [] })), + )); + setActionData$ = createEffect(() => this.actions$.pipe( ofType(marketStateActions.setMarketData), map(({ marketData }) => marketData.filter((item) => !!item.auction)), diff --git a/marketplace/src/app/state/market/market-state.reducers.ts b/marketplace/src/app/state/market/market-state.reducers.ts index c89be51c..a438719c 100644 --- a/marketplace/src/app/state/market/market-state.reducers.ts +++ b/marketplace/src/app/state/market/market-state.reducers.ts @@ -44,9 +44,20 @@ export const marketStateReducer: ActionReducer = createRedu return setMarketType }), on(actions.setMarketSlug, (state, { marketSlug }) => { + if (state.marketSlug === marketSlug) return state; + const setMarketSlug = { ...state, - marketSlug + marketSlug, + marketData: initialState.marketData, + owned: initialState.owned, + listings: initialState.listings, + bids: initialState.bids, + all: initialState.all, + auctions: initialState.auctions, + activeMarketRouteData: initialState.activeMarketRouteData, + selectedPhunks: initialState.selectedPhunks, + pagination: initialState.pagination, }; return setMarketSlug; }), From 6453bab44e3636878c5b7157feecf71233701bd5 Mon Sep 17 00:00:00 2001 From: Snepsid <101685992+Snepsid@users.noreply.github.com> Date: Fri, 15 May 2026 14:18:28 -0400 Subject: [PATCH 2/3] fix recent activity fetch races --- marketplace/src/app/services/data.service.ts | 36 ++++++++++++------- .../app/state/market/market-state.effects.ts | 5 ++- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/marketplace/src/app/services/data.service.ts b/marketplace/src/app/services/data.service.ts index 43af64a7..a9ae2f73 100644 --- a/marketplace/src/app/services/data.service.ts +++ b/marketplace/src/app/services/data.service.ts @@ -5,7 +5,7 @@ import { Store } from '@ngrx/store'; import { createClient, RealtimePostgresUpdatePayload, RealtimePostgresInsertPayload } from '@supabase/supabase-js' -import { Observable, of, from, forkJoin, firstValueFrom, EMPTY, timer, merge, filter, share, catchError, debounceTime, expand, map, reduce, switchMap, tap, distinctUntilChanged, BehaviorSubject } from 'rxjs'; +import { Observable, of, from, forkJoin, firstValueFrom, EMPTY, timer, merge, filter, share, catchError, debounceTime, expand, map, reduce, switchMap, tap, distinctUntilChanged, BehaviorSubject, defer, retry } from 'rxjs'; import { Web3Service } from '@/services/web3.service'; import { AttributesService } from '@/services/attributes.service'; @@ -316,19 +316,21 @@ export class DataService { type: EventType, slug: string, ): Observable { - const query = supabase.rpc( - 'fetch_events' + this.suffix, - { - p_limit: limit, - p_type: type && type !== 'All' ? type : null, - p_collection_slug: slug, - p_offset: offset, - } - ); - - const rpcFetch$ = from(query).pipe( + const rpcFetch$ = defer(() => from( + supabase.rpc( + 'fetch_events' + this.suffix, + { + p_limit: limit, + p_type: type && type !== 'All' ? type : null, + p_collection_slug: slug, + p_offset: offset, + } + ) + )).pipe( map((res: any) => { - const result = res.data?.map((tx: any) => { + if (res.error) throw res.error; + + const result = (res.data || []).map((tx: any) => { let type = tx.type; if (type === 'transfer') { if (tx.to?.toLowerCase() === environment.bridgeAddress) type = 'bridgeOut'; @@ -338,6 +340,14 @@ export class DataService { }); return result; }), + retry({ + count: 2, + delay: (_err, retryCount) => timer(retryCount * 500), + }), + catchError((err) => { + console.warn('Failed to fetch recent activity events', { slug, type, offset, err }); + return of([]); + }), ); return merge( diff --git a/marketplace/src/app/state/market/market-state.effects.ts b/marketplace/src/app/state/market/market-state.effects.ts index 512f901b..3772d3cc 100644 --- a/marketplace/src/app/state/market/market-state.effects.ts +++ b/marketplace/src/app/state/market/market-state.effects.ts @@ -154,10 +154,13 @@ export class MarketStateEffects { if (page === 0) return events; return [...acc, ...events]; }, [] as Event[]), + map((events) => ({ events, marketSlug })), ); }), + withLatestFrom(this.store.select(marketStateSelectors.selectMarketSlug)), + filter(([{ marketSlug }, currentMarketSlug]) => marketSlug === currentMarketSlug), // tap((events) => console.log('fetchEvents$', events)), - map((events) => dataStateActions.setEvents({ events })), + map(([{ events }]) => dataStateActions.setEvents({ events })), )); clearEventsOnMarketSlugChange$ = createEffect(() => this.actions$.pipe( From 9f901a1448b2a774945a16a4b08156626794368f Mon Sep 17 00:00:00 2001 From: Snepsid <101685992+Snepsid@users.noreply.github.com> Date: Fri, 15 May 2026 16:26:10 -0400 Subject: [PATCH 3/3] fix recent activity query reliability --- marketplace/src/app/services/data.service.ts | 13 +++++-- ...00000_add_event_activity_query_indexes.sql | 35 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 supabase/migrations/20250128000000_add_event_activity_query_indexes.sql diff --git a/marketplace/src/app/services/data.service.ts b/marketplace/src/app/services/data.service.ts index a9ae2f73..ba65b016 100644 --- a/marketplace/src/app/services/data.service.ts +++ b/marketplace/src/app/services/data.service.ts @@ -836,13 +836,14 @@ export class DataService { }; // Initial fetch - const rpcFetch$: Observable = from( + const rpcFetch$: Observable = defer(() => from( supabase.rpc( 'fetch_collections_with_previews' + this.suffix, params ) - ).pipe( + )).pipe( map((res: any) => { + if (res.error) throw res.error; if (!res.data) return []; return res.data .map((item: any) => ({ @@ -857,6 +858,14 @@ export class DataService { return true; }); }), + retry({ + count: 2, + delay: (_err, retryCount) => timer(retryCount * 500), + }), + catchError((err) => { + console.warn('Failed to fetch collections', { onlyDisabled, err }); + return of([]); + }), // tap((res) => console.log('fetchCollections', res)), ); diff --git a/supabase/migrations/20250128000000_add_event_activity_query_indexes.sql b/supabase/migrations/20250128000000_add_event_activity_query_indexes.sql new file mode 100644 index 00000000..9b974815 --- /dev/null +++ b/supabase/migrations/20250128000000_add_event_activity_query_indexes.sql @@ -0,0 +1,35 @@ +CREATE INDEX IF NOT EXISTS ethscriptions_slug_hash_id_idx +ON public.ethscriptions (slug, "hashId"); + +CREATE INDEX IF NOT EXISTS events_hash_id_block_timestamp_tx_id_idx +ON public.events ("hashId", "blockTimestamp" DESC, "txId"); + +CREATE INDEX IF NOT EXISTS events_type_hash_id_block_timestamp_tx_id_idx +ON public.events (type, "hashId", "blockTimestamp" DESC, "txId"); + +CREATE INDEX IF NOT EXISTS events_recent_activity_order_idx +ON public.events ("blockTimestamp" DESC, "txId", "hashId") +INCLUDE ("from", "to", type, value) +WHERE + type <> 'PhunkNoLongerForSale' + AND "to" <> '0xd3418772623be1a3cc6b6d45cb46420cedd9154a' + AND "to" <> '' + AND "from" <> ''; + +CREATE INDEX IF NOT EXISTS ethscriptions_sepolia_slug_hash_id_idx +ON public.ethscriptions_sepolia (slug, "hashId"); + +CREATE INDEX IF NOT EXISTS events_sepolia_hash_id_block_timestamp_tx_id_idx +ON public.events_sepolia ("hashId", "blockTimestamp" DESC, "txId"); + +CREATE INDEX IF NOT EXISTS events_sepolia_type_hash_id_block_timestamp_tx_id_idx +ON public.events_sepolia (type, "hashId", "blockTimestamp" DESC, "txId"); + +CREATE INDEX IF NOT EXISTS events_sepolia_recent_activity_order_idx +ON public.events_sepolia ("blockTimestamp" DESC, "txId", "hashId") +INCLUDE ("from", "to", type, value) +WHERE + type <> 'PhunkNoLongerForSale' + AND "to" <> '0x3dfbc8c62d3ce0059bdaf21787ec24d5d116fe1e' + AND "to" <> '0xc6a824d8cce7c946a3f35879694b9261a36fc823' + AND "from" <> '0xc6a824d8cce7c946a3f35879694b9261a36fc823';