/
useCollectionFetch.tsx
155 lines (134 loc) · 4.27 KB
/
useCollectionFetch.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import { useCallback, useEffect, useMemo, useState } from "react";
import { Entity, EntitySchemaResolver, FilterValues } from "../../models";
import { useDataSource } from "./useDataSource";
/**
* @category Hooks and utilities
*/
export interface CollectionFetchProps<M extends { [Key: string]: any }> {
/**
* Absolute collection path
*/
path: string;
/**
* Schema of the entity displayed by this collection
*/
schemaResolver: EntitySchemaResolver<M>;
/**
* Number of entities to fetch
*/
itemCount?: number;
/**
* List of entities that will be displayed on top, no matter the ordering.
* This is used for reference fields selection
*/
entitiesDisplayedFirst?: Entity<M>[];
/**
* Filter the fetched data by the property
*/
filterValues?: FilterValues<M>;
/**
* Sort the results by
*/
sortBy?: [Extract<keyof M, string>, "asc" | "desc"];
/**
* Search string
*/
searchString?: string;
}
/**
* @category Hooks and utilities
*/
export interface CollectionFetchResult<M extends { [Key: string]: any }> {
data: Entity<M>[]
dataLoading: boolean,
noMoreToLoad: boolean,
dataLoadingError?: Error
}
/**
* This hook is used to fetch collections using a given schema
* @param path
* @param schemaResolver
* @param filterValues
* @param sortBy
* @param itemCount
* @param searchString
* @param entitiesDisplayedFirst
* @category Hooks and utilities
*/
export function useCollectionFetch<M>(
{
path,
schemaResolver,
filterValues,
sortBy,
itemCount,
searchString,
entitiesDisplayedFirst
}: CollectionFetchProps<M>): CollectionFetchResult<M> {
const sortByProperty = sortBy ? sortBy[0] : undefined;
const currentSort = sortBy ? sortBy[1] : undefined;
const dataSource = useDataSource();
const initialEntities = useMemo(() => entitiesDisplayedFirst ? entitiesDisplayedFirst.filter(e => !!e.values) : [], [entitiesDisplayedFirst]);
const [data, setData] = useState<Entity<M>[]>(initialEntities);
const [dataLoading, setDataLoading] = useState<boolean>(false);
const [dataLoadingError, setDataLoadingError] = useState<Error | undefined>();
const [noMoreToLoad, setNoMoreToLoad] = useState<boolean>(false);
const updateData = useCallback((entities: Entity<M>[]) => {
if (!initialEntities) {
setData(entities);
} else {
const displayedFirstId = new Set(initialEntities.map((e) => e.id));
setData([...initialEntities, ...entities.filter((e) => !displayedFirstId.has(e.id))]);
}
}, [initialEntities]);
useEffect(() => {
setDataLoading(true);
const onEntitiesUpdate = (entities: Entity<M>[]) => {
setDataLoading(false);
setDataLoadingError(undefined);
updateData(entities);
setNoMoreToLoad(!itemCount || entities.length < itemCount);
};
const onError = (error: Error) => {
console.error("ERROR", error);
setDataLoading(false);
setData([]);
setDataLoadingError(error);
};
if (dataSource.listenCollection) {
return dataSource.listenCollection<M>({
path: path,
schema: schemaResolver,
onUpdate: onEntitiesUpdate,
onError,
searchString,
filter: filterValues,
limit: itemCount,
startAfter: undefined,
orderBy: sortByProperty,
order: currentSort
});
} else {
dataSource.fetchCollection<M>({
path: path,
schema: schemaResolver,
searchString,
filter: filterValues,
limit: itemCount,
startAfter: undefined,
orderBy: sortByProperty,
order: currentSort
})
.then(onEntitiesUpdate)
.catch(onError);
return () => {
};
}
}, [path, itemCount, currentSort, sortByProperty, filterValues, searchString]);
return {
data,
dataLoading,
dataLoadingError,
noMoreToLoad
};
}