pl-fe: migrate events lists to tanstack query

Signed-off-by: Nicole Mikołajczyk <git@mkljczk.pl>
This commit is contained in:
Nicole Mikołajczyk
2025-06-01 07:18:14 +02:00
parent d3ece86bfb
commit 603da0fa01
4 changed files with 35 additions and 103 deletions

View File

@ -6,7 +6,7 @@ import toast from 'pl-fe/toast';
import { importEntities } from './importer';
import { STATUS_FETCH_SOURCE_FAIL, STATUS_FETCH_SOURCE_REQUEST, STATUS_FETCH_SOURCE_SUCCESS } from './statuses';
import type { CreateEventParams, Location, MediaAttachment, PaginatedResponse, Status } from 'pl-api';
import type { CreateEventParams, Location, MediaAttachment, Status } from 'pl-api';
import type { AppDispatch, RootState } from 'pl-fe/store';
const EVENT_JOIN_REQUEST = 'EVENT_JOIN_REQUEST' as const;
@ -19,13 +19,6 @@ const EVENT_COMPOSE_CANCEL = 'EVENT_COMPOSE_CANCEL' as const;
const EVENT_FORM_SET = 'EVENT_FORM_SET' as const;
const RECENT_EVENTS_FETCH_REQUEST = 'RECENT_EVENTS_FETCH_REQUEST' as const;
const RECENT_EVENTS_FETCH_SUCCESS = 'RECENT_EVENTS_FETCH_SUCCESS' as const;
const RECENT_EVENTS_FETCH_FAIL = 'RECENT_EVENTS_FETCH_FAIL' as const;
const JOINED_EVENTS_FETCH_REQUEST = 'JOINED_EVENTS_FETCH_REQUEST' as const;
const JOINED_EVENTS_FETCH_SUCCESS = 'JOINED_EVENTS_FETCH_SUCCESS' as const;
const JOINED_EVENTS_FETCH_FAIL = 'JOINED_EVENTS_FETCH_FAIL' as const;
const noOp = () => new Promise(f => f(undefined));
const messages = defineMessages({
@ -190,61 +183,13 @@ const initEventEdit = (statusId: string) => (dispatch: AppDispatch, getState: ()
});
};
const fetchRecentEvents = () =>
(dispatch: AppDispatch, getState: () => RootState) => {
if (getState().status_lists.recent_events?.isLoading) {
return;
}
dispatch<EventsAction>({ type: RECENT_EVENTS_FETCH_REQUEST });
return getClient(getState()).timelines.publicTimeline({
only_events: true,
}).then(response => {
dispatch(importEntities({ statuses: response.items }));
dispatch<EventsAction>({
type: RECENT_EVENTS_FETCH_SUCCESS,
statuses: response.items,
next: response.next,
});
}).catch(error => {
dispatch<EventsAction>({ type: RECENT_EVENTS_FETCH_FAIL, error });
});
};
const fetchJoinedEvents = () =>
(dispatch: AppDispatch, getState: () => RootState) => {
if (getState().status_lists.joined_events?.isLoading) {
return;
}
dispatch<EventsAction>({ type: JOINED_EVENTS_FETCH_REQUEST });
getClient(getState).events.getJoinedEvents().then(response => {
dispatch(importEntities({ statuses: response.items }));
dispatch<EventsAction>({
type: JOINED_EVENTS_FETCH_SUCCESS,
statuses: response.items,
next: response.next,
});
}).catch(error => {
dispatch<EventsAction>({ type: JOINED_EVENTS_FETCH_FAIL, error });
});
};
type EventsAction =
| ReturnType<typeof joinEventRequest>
| ReturnType<typeof joinEventFail>
| ReturnType<typeof leaveEventRequest>
| ReturnType<typeof leaveEventFail>
| ReturnType<typeof cancelEventCompose>
| EventFormSetAction
| { type: typeof RECENT_EVENTS_FETCH_REQUEST }
| { type: typeof RECENT_EVENTS_FETCH_SUCCESS; statuses: Array<Status>; next: (() => Promise<PaginatedResponse<Status>>) | null }
| { type: typeof RECENT_EVENTS_FETCH_FAIL; error: unknown }
| { type: typeof JOINED_EVENTS_FETCH_REQUEST }
| { type: typeof JOINED_EVENTS_FETCH_SUCCESS; statuses: Array<Status>; next: (() => Promise<PaginatedResponse<Status>>) | null }
| { type: typeof JOINED_EVENTS_FETCH_FAIL; error: unknown }
| EventFormSetAction;
export {
EVENT_JOIN_REQUEST,
@ -253,19 +198,11 @@ export {
EVENT_LEAVE_FAIL,
EVENT_COMPOSE_CANCEL,
EVENT_FORM_SET,
RECENT_EVENTS_FETCH_REQUEST,
RECENT_EVENTS_FETCH_SUCCESS,
RECENT_EVENTS_FETCH_FAIL,
JOINED_EVENTS_FETCH_REQUEST,
JOINED_EVENTS_FETCH_SUCCESS,
JOINED_EVENTS_FETCH_FAIL,
submitEvent,
joinEvent,
leaveEvent,
fetchEventIcs,
cancelEventCompose,
initEventEdit,
fetchRecentEvents,
fetchJoinedEvents,
type EventsAction,
};

View File

@ -1,9 +1,8 @@
import React, { useCallback, useEffect, useState } from 'react';
import React, { useCallback, useState } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { Link } from 'react-router-dom';
import ReactSwipeableViews from 'react-swipeable-views';
import { fetchJoinedEvents, fetchRecentEvents } from 'pl-fe/actions/events';
import EventPreview from 'pl-fe/components/event-preview';
import Button from 'pl-fe/components/ui/button';
import Card, { CardBody, CardHeader, CardTitle } from 'pl-fe/components/ui/card';
@ -11,8 +10,8 @@ import Column from 'pl-fe/components/ui/column';
import HStack from 'pl-fe/components/ui/hstack';
import Icon from 'pl-fe/components/ui/icon';
import PlaceholderEventPreview from 'pl-fe/features/placeholder/components/placeholder-event-preview';
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
import { useJoinedEvents, useRecentEvents } from 'pl-fe/queries/status-lists/use-events-lists';
import { makeGetStatus } from 'pl-fe/selectors';
const messages = defineMessages({
@ -91,17 +90,8 @@ const EventCarousel: React.FC<IEventCarousel> = ({ statusIds, isLoading, emptyMe
const EventsPage = () => {
const intl = useIntl();
const dispatch = useAppDispatch();
const recentEvents = useAppSelector((state) => state.status_lists.recent_events!.items);
const recentEventsLoading = useAppSelector((state) => state.status_lists.recent_events!.isLoading);
const joinedEvents = useAppSelector((state) => state.status_lists.joined_events!.items);
const joinedEventsLoading = useAppSelector((state) => state.status_lists.joined_events!.isLoading);
useEffect(() => {
dispatch(fetchRecentEvents());
dispatch(fetchJoinedEvents());
}, []);
const { data: recentEvents = [], isLoading: recentEventsLoading } = useRecentEvents();
const { data: joinedEvents = [], isLoading: joinedEventsLoading } = useJoinedEvents();
return (
<Column label={intl.formatMessage(messages.title)}>

View File

@ -0,0 +1,28 @@
import { useInfiniteQuery } from '@tanstack/react-query';
import { makePaginatedResponseQueryOptions } from '../utils/make-paginated-response-query-options';
import { minifyStatusList } from '../utils/minify-list';
const recentEventsQueryOptions = makePaginatedResponseQueryOptions(
() => ['statusLists', 'recentEvents'],
(client) => client.timelines.publicTimeline({
only_events: true,
}).then(minifyStatusList),
)();
const useRecentEvents = () => useInfiniteQuery({
...recentEventsQueryOptions,
staleTime: 5 * 60 * 1000, // 5 minutes
});
const joinedEventsQueryOptions = makePaginatedResponseQueryOptions(
() => ['statusLists', 'joinedEvents'],
(client) => client.events.getJoinedEvents().then(minifyStatusList),
)();
const useJoinedEvents = () => useInfiniteQuery({
...joinedEventsQueryOptions,
staleTime: 5 * 60 * 1000, // 5 minutes
});
export { useRecentEvents, useJoinedEvents };

View File

@ -9,15 +9,6 @@ import {
BOOKMARKED_STATUSES_EXPAND_FAIL,
type BookmarksAction,
} from 'pl-fe/actions/bookmarks';
import {
RECENT_EVENTS_FETCH_REQUEST,
RECENT_EVENTS_FETCH_SUCCESS,
RECENT_EVENTS_FETCH_FAIL,
JOINED_EVENTS_FETCH_REQUEST,
JOINED_EVENTS_FETCH_SUCCESS,
JOINED_EVENTS_FETCH_FAIL,
type EventsAction,
} from 'pl-fe/actions/events';
import {
FAVOURITED_STATUSES_FETCH_REQUEST,
FAVOURITED_STATUSES_FETCH_SUCCESS,
@ -65,8 +56,6 @@ const initialState: State = {
favourites: newStatusList(),
bookmarks: newStatusList(),
pins: newStatusList(),
recent_events: newStatusList(),
joined_events: newStatusList(),
};
const getStatusId = (status: string | Pick<Status, 'id'>) => typeof status === 'string' ? status : status.id;
@ -127,7 +116,7 @@ const removeBookmarkFromLists = (state: State, status: Pick<Status, 'id' | 'book
}
};
const statusLists = (state = initialState, action: BookmarksAction | EventsAction | FavouritesAction | InteractionsAction | PinStatusesAction | StatusesAction): State => {
const statusLists = (state = initialState, action: BookmarksAction | FavouritesAction | InteractionsAction | PinStatusesAction | StatusesAction): State => {
switch (action.type) {
case FAVOURITED_STATUSES_FETCH_REQUEST:
case FAVOURITED_STATUSES_EXPAND_REQUEST:
@ -169,18 +158,6 @@ const statusLists = (state = initialState, action: BookmarksAction | EventsActio
return create(state, draft => prependOneToList(draft, 'pins', action.status));
case UNPIN_SUCCESS:
return create(state, draft => removeOneFromList(draft, 'pins', action.status));
case RECENT_EVENTS_FETCH_REQUEST:
return create(state, draft => setLoading(draft, 'recent_events', true));
case RECENT_EVENTS_FETCH_FAIL:
return create(state, draft => setLoading(draft, 'recent_events', false));
case RECENT_EVENTS_FETCH_SUCCESS:
return create(state, draft => normalizeList(draft, 'recent_events', action.statuses, action.next));
case JOINED_EVENTS_FETCH_REQUEST:
return create(state, draft => setLoading(draft, 'joined_events', true));
case JOINED_EVENTS_FETCH_FAIL:
return create(state, draft => setLoading(draft, 'joined_events', false));
case JOINED_EVENTS_FETCH_SUCCESS:
return create(state, draft => normalizeList(draft, 'joined_events', action.statuses, action.next));
default:
return state;
}