Migrate to external library for interacting with API
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
@ -35,7 +35,7 @@ interface EntityCallbacks<Value, Error = unknown> {
|
||||
* Passed into hooks to make requests.
|
||||
* Must return a response.
|
||||
*/
|
||||
type EntityFn<T> = (value: T) => Promise<PlApiResponse>
|
||||
type EntityFn<T> = (value: T) => Promise<T>
|
||||
|
||||
export type {
|
||||
EntitySchema,
|
||||
|
||||
@ -23,7 +23,7 @@ interface UseBatchedEntitiesOpts<TEntity extends Entity> {
|
||||
const useBatchedEntities = <TEntity extends Entity>(
|
||||
expandedPath: ExpandedEntitiesPath,
|
||||
ids: string[],
|
||||
entityFn: EntityFn<string[]>,
|
||||
entityFn: EntityFn<TEntity[]>,
|
||||
opts: UseBatchedEntitiesOpts<TEntity> = {},
|
||||
) => {
|
||||
const getState = useGetState();
|
||||
@ -54,10 +54,10 @@ const useBatchedEntities = <TEntity extends Entity>(
|
||||
dispatch(entitiesFetchRequest(entityType, listKey));
|
||||
try {
|
||||
const response = await entityFn(filteredIds);
|
||||
const entities = filteredArray(schema).parse(response.json);
|
||||
const entities = filteredArray(schema).parse(response);
|
||||
dispatch(entitiesFetchSuccess(entities, entityType, listKey, 'end', {
|
||||
next: undefined,
|
||||
prev: undefined,
|
||||
next: null,
|
||||
prev: null,
|
||||
totalCount: undefined,
|
||||
fetching: false,
|
||||
fetched: true,
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
import { useEffect } from 'react';
|
||||
import z from 'zod';
|
||||
|
||||
import { getNextLink, getPrevLink } from 'soapbox/api';
|
||||
import { useClient } from 'soapbox/hooks';
|
||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch';
|
||||
import { useAppSelector } from 'soapbox/hooks/useAppSelector';
|
||||
import { useGetState } from 'soapbox/hooks/useGetState';
|
||||
import { filteredArray } from 'soapbox/schemas/utils';
|
||||
import { realNumberSchema } from 'soapbox/utils/numbers';
|
||||
|
||||
import { entitiesFetchFail, entitiesFetchRequest, entitiesFetchSuccess, invalidateEntityList } from '../actions';
|
||||
import { selectEntities, selectListState, useListState } from '../selectors';
|
||||
@ -16,6 +14,7 @@ import { parseEntitiesPath } from './utils';
|
||||
|
||||
import type { EntityFn, EntitySchema, ExpandedEntitiesPath } from './types';
|
||||
import type { Entity } from '../types';
|
||||
import type { PaginatedResponse } from 'pl-api';
|
||||
|
||||
/** Additional options for the hook. */
|
||||
interface UseEntitiesOpts<TEntity extends Entity> {
|
||||
@ -58,7 +57,7 @@ const useEntities = <TEntity extends Entity>(
|
||||
const next = useListState(path, 'next');
|
||||
const prev = useListState(path, 'prev');
|
||||
|
||||
const fetchPage = async(req: EntityFn<void>, pos: 'start' | 'end', overwrite = false): Promise<void> => {
|
||||
const fetchPage = async(req: () => Promise<PaginatedResponse<any>>, pos: 'start' | 'end', overwrite = false): Promise<void> => {
|
||||
// Get `isFetching` state from the store again to prevent race conditions.
|
||||
const isFetching = selectListState(getState(), path, 'fetching');
|
||||
if (isFetching) return;
|
||||
@ -66,14 +65,12 @@ const useEntities = <TEntity extends Entity>(
|
||||
dispatch(entitiesFetchRequest(entityType, listKey));
|
||||
try {
|
||||
const response = await req();
|
||||
const entities = filteredArray(schema).parse(response.json);
|
||||
const parsedCount = realNumberSchema.safeParse(response.headers.get('x-total-count'));
|
||||
const totalCount = parsedCount.success ? parsedCount.data : undefined;
|
||||
const entities = filteredArray(schema).parse(response);
|
||||
|
||||
dispatch(entitiesFetchSuccess(entities, entityType, listKey, pos, {
|
||||
next: getNextLink(response),
|
||||
prev: getPrevLink(response),
|
||||
totalCount: Number(totalCount) >= entities.length ? totalCount : undefined,
|
||||
next: response.next,
|
||||
prev: response.previous,
|
||||
totalCount: undefined,
|
||||
fetching: false,
|
||||
fetched: true,
|
||||
error: null,
|
||||
@ -91,13 +88,13 @@ const useEntities = <TEntity extends Entity>(
|
||||
|
||||
const fetchNextPage = async(): Promise<void> => {
|
||||
if (next) {
|
||||
await fetchPage(() => client.request(next), 'end');
|
||||
await fetchPage(() => next(), 'end');
|
||||
}
|
||||
};
|
||||
|
||||
const fetchPreviousPage = async(): Promise<void> => {
|
||||
if (prev) {
|
||||
await fetchPage(() => client.request(prev), 'start');
|
||||
await fetchPage(() => prev(), 'start');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ interface UseEntityOpts<TEntity extends Entity> {
|
||||
|
||||
const useEntity = <TEntity extends Entity>(
|
||||
path: EntityPath,
|
||||
entityFn: EntityFn<void>,
|
||||
entityFn: EntityFn<TEntity>,
|
||||
opts: UseEntityOpts<TEntity> = {},
|
||||
) => {
|
||||
const [isFetching, setPromise] = useLoading(true);
|
||||
@ -46,7 +46,7 @@ const useEntity = <TEntity extends Entity>(
|
||||
const fetchEntity = async () => {
|
||||
try {
|
||||
const response = await setPromise(entityFn());
|
||||
const entity = schema.parse(response.json);
|
||||
const entity = schema.parse(response);
|
||||
dispatch(importEntities([entity], entityType));
|
||||
} catch (e) {
|
||||
setError(e);
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import type { PaginatedResponse } from 'pl-api';
|
||||
|
||||
/** A Mastodon API entity. */
|
||||
interface Entity {
|
||||
/** Unique ID for the entity (usually the primary key in the database). */
|
||||
@ -20,9 +22,9 @@ interface EntityList {
|
||||
/** Fetch state for an entity list. */
|
||||
interface EntityListState {
|
||||
/** Next URL for pagination, if any. */
|
||||
next: string | undefined;
|
||||
next: (() => Promise<PaginatedResponse<any>>) | null;
|
||||
/** Previous URL for pagination, if any. */
|
||||
prev: string | undefined;
|
||||
prev: (() => Promise<PaginatedResponse<any>>) | null;
|
||||
/** Total number of items according to the API. */
|
||||
totalCount: number | undefined;
|
||||
/** Error returned from the API, if any. */
|
||||
|
||||
Reference in New Issue
Block a user