EntityStore: let totalCount be undefined, don't try to set it from the local count

This commit is contained in:
Alex Gleason 2023-03-22 19:05:57 -05:00
parent f016ac1e6d
commit c4d0dd568e
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
5 changed files with 20 additions and 7 deletions

View File

@ -4,6 +4,7 @@ import z from 'zod';
import { getNextLink, getPrevLink } from 'soapbox/api'; import { getNextLink, getPrevLink } from 'soapbox/api';
import { useApi, useAppDispatch, useAppSelector, useGetState } from 'soapbox/hooks'; import { useApi, useAppDispatch, useAppSelector, useGetState } from 'soapbox/hooks';
import { filteredArray } from 'soapbox/schemas/utils'; import { filteredArray } from 'soapbox/schemas/utils';
import { realNumberSchema } from 'soapbox/utils/numbers';
import { entitiesFetchFail, entitiesFetchRequest, entitiesFetchSuccess, invalidateEntityList } from '../actions'; import { entitiesFetchFail, entitiesFetchRequest, entitiesFetchSuccess, invalidateEntityList } from '../actions';
@ -63,12 +64,12 @@ function useEntities<TEntity extends Entity>(
const response = await api.get(url); const response = await api.get(url);
const schema = opts.schema || z.custom<TEntity>(); const schema = opts.schema || z.custom<TEntity>();
const entities = filteredArray(schema).parse(response.data); const entities = filteredArray(schema).parse(response.data);
const numItems = (selectList(getState(), path)?.ids.size || 0) + entities.length; const parsedCount = realNumberSchema.safeParse(response.headers['x-total-count']);
dispatch(entitiesFetchSuccess(entities, entityType, listKey, { dispatch(entitiesFetchSuccess(entities, entityType, listKey, {
next: getNextLink(response), next: getNextLink(response),
prev: getPrevLink(response), prev: getPrevLink(response),
totalCount: Number(response.headers['x-total-count'] ?? numItems) || 0, totalCount: parsedCount.success ? parsedCount.data : undefined,
fetching: false, fetching: false,
fetched: true, fetched: true,
error: null, error: null,

View File

@ -71,7 +71,10 @@ const deleteEntities = (
for (const list of Object.values(cache.lists)) { for (const list of Object.values(cache.lists)) {
if (list) { if (list) {
list.ids.delete(id); list.ids.delete(id);
list.state.totalCount--;
if (typeof list.state.totalCount === 'number') {
list.state.totalCount--;
}
} }
} }
} }
@ -94,7 +97,10 @@ const dismissEntities = (
if (list) { if (list) {
for (const id of ids) { for (const id of ids) {
list.ids.delete(id); list.ids.delete(id);
list.state.totalCount--;
if (typeof list.state.totalCount === 'number') {
list.state.totalCount--;
}
} }
draft[entityType] = cache; draft[entityType] = cache;

View File

@ -24,7 +24,7 @@ interface EntityListState {
/** Previous URL for pagination, if any. */ /** Previous URL for pagination, if any. */
prev: string | undefined prev: string | undefined
/** Total number of items according to the API. */ /** Total number of items according to the API. */
totalCount: number totalCount: number | undefined
/** Error returned from the API, if any. */ /** Error returned from the API, if any. */
error: any error: any
/** Whether data has already been fetched */ /** Whether data has already been fetched */

View File

@ -13,8 +13,10 @@ const updateList = (list: EntityList, entities: Entity[]): EntityList => {
const newIds = entities.map(entity => entity.id); const newIds = entities.map(entity => entity.id);
const ids = new Set([...Array.from(list.ids), ...newIds]); const ids = new Set([...Array.from(list.ids), ...newIds]);
const sizeDiff = ids.size - list.ids.size; if (typeof list.state.totalCount === 'number') {
list.state.totalCount += sizeDiff; const sizeDiff = ids.size - list.ids.size;
list.state.totalCount += sizeDiff;
}
return { return {
...list, ...list,

View File

@ -1,9 +1,13 @@
import React from 'react'; import React from 'react';
import { FormattedNumber } from 'react-intl'; import { FormattedNumber } from 'react-intl';
import { z } from 'zod';
/** Check if a value is REALLY a number. */ /** Check if a value is REALLY a number. */
export const isNumber = (value: unknown): value is number => typeof value === 'number' && !isNaN(value); export const isNumber = (value: unknown): value is number => typeof value === 'number' && !isNaN(value);
/** The input is a number and is not NaN. */
export const realNumberSchema = z.coerce.number().refine(n => !isNaN(n));
export const secondsToDays = (seconds: number) => Math.floor(seconds / (3600 * 24)); export const secondsToDays = (seconds: number) => Math.floor(seconds / (3600 * 24));
const roundDown = (num: number) => { const roundDown = (num: number) => {