Rework
This commit is contained in:
@@ -136,7 +136,7 @@ export const GalleryBarAndListHeader: React.FC<
|
||||
if (shouldHide) return;
|
||||
|
||||
setFileListHeader({
|
||||
item:
|
||||
component:
|
||||
mode != "people" ? (
|
||||
<CollectionHeader
|
||||
{...{
|
||||
|
||||
@@ -31,9 +31,9 @@ import {
|
||||
} from "ente-new/photos/components/utils/thumbnail-grid-layout";
|
||||
import { PseudoCollectionID } from "ente-new/photos/services/collection-summary";
|
||||
import { t } from "i18next";
|
||||
import memoize from "memoize-one";
|
||||
import React, {
|
||||
memo,
|
||||
useCallback,
|
||||
useDeferredValue,
|
||||
useEffect,
|
||||
useMemo,
|
||||
@@ -59,7 +59,7 @@ export interface FileListHeaderOrFooter {
|
||||
/**
|
||||
* The component itself.
|
||||
*/
|
||||
item: React.ReactNode;
|
||||
component: React.ReactNode;
|
||||
/**
|
||||
* The height of the component (in px).
|
||||
*/
|
||||
@@ -70,7 +70,11 @@ export interface FileListHeaderOrFooter {
|
||||
* Data needed to render each row in the variable size list that comprises the
|
||||
* file list.
|
||||
*/
|
||||
interface FileListRow {
|
||||
interface FileListItem {
|
||||
/**
|
||||
* The height of the row that will render this item.
|
||||
*/
|
||||
height: number;
|
||||
/**
|
||||
* An optional tag that can be used to identify item types for conditional
|
||||
* behaviour.
|
||||
@@ -81,12 +85,10 @@ interface FileListRow {
|
||||
date?: string | null;
|
||||
dates?: { date: string; span: number }[];
|
||||
groups?: number[];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
item?: any;
|
||||
id?: string;
|
||||
height?: number;
|
||||
fileSize?: number;
|
||||
fileCount?: number;
|
||||
/**
|
||||
* The React component that is the rendered representation of the item.
|
||||
*/
|
||||
component?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface FileListAnnotatedFile {
|
||||
@@ -218,8 +220,8 @@ export const FileList: React.FC<FileListProps> = ({
|
||||
emailByUserID,
|
||||
onItemClick,
|
||||
}) => {
|
||||
const [_rows, setRows] = useState<FileListRow[]>([]);
|
||||
const rows = useDeferredValue(_rows);
|
||||
const [_items, setItems] = useState<FileListItem[]>([]);
|
||||
const items = useDeferredValue(_items);
|
||||
|
||||
const listRef = useRef<VariableSizeList | null>(null);
|
||||
|
||||
@@ -247,8 +249,6 @@ export const FileList: React.FC<FileListProps> = ({
|
||||
// itemHeight,
|
||||
// gap,
|
||||
} = layoutParams;
|
||||
// TODO(RE):
|
||||
const listItemHeight = layoutParams.itemHeight + layoutParams.gap;
|
||||
|
||||
useEffect(() => {
|
||||
// Since width and height are dependencies, there might be too many
|
||||
@@ -259,59 +259,98 @@ export const FileList: React.FC<FileListProps> = ({
|
||||
// another update when processing one, React will restart the background
|
||||
// rerender from scratch.
|
||||
|
||||
let rows: FileListRow[] = [];
|
||||
let items: FileListItem[] = [];
|
||||
|
||||
if (header) rows.push(asFullSpanListItem(header));
|
||||
if (header) items.push(asFullSpanListItem(header));
|
||||
|
||||
const { isSmallerLayout, columns } = layoutParams;
|
||||
const fileItemHeight = layoutParams.itemHeight + layoutParams.gap;
|
||||
if (disableGrouping) {
|
||||
let listItemIndex = columns;
|
||||
annotatedFiles.forEach((item, index) => {
|
||||
for (const [index, af] of annotatedFiles.entries()) {
|
||||
if (listItemIndex < columns) {
|
||||
rows[rows.length - 1]!.items!.push(item);
|
||||
items[items.length - 1]!.items!.push(af);
|
||||
listItemIndex++;
|
||||
} else {
|
||||
listItemIndex = 1;
|
||||
rows.push({
|
||||
items.push({
|
||||
height: fileItemHeight,
|
||||
tag: "file",
|
||||
items: [item],
|
||||
items: [af],
|
||||
itemStartIndex: index,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
groupByTime(rows);
|
||||
let listItemIndex = 0;
|
||||
let lastCreationTime: number | undefined;
|
||||
for (const [index, af] of annotatedFiles.entries()) {
|
||||
const creationTime = fileCreationTime(af.file) / 1000;
|
||||
if (
|
||||
!lastCreationTime ||
|
||||
!isSameDay(
|
||||
new Date(creationTime),
|
||||
new Date(lastCreationTime),
|
||||
)
|
||||
) {
|
||||
lastCreationTime = creationTime;
|
||||
|
||||
items.push({
|
||||
height: dateContainerHeight,
|
||||
tag: "date",
|
||||
date: af.timelineDateString,
|
||||
});
|
||||
items.push({
|
||||
height: fileItemHeight,
|
||||
tag: "file",
|
||||
items: [af],
|
||||
itemStartIndex: index,
|
||||
});
|
||||
listItemIndex = 1;
|
||||
} else if (listItemIndex < columns) {
|
||||
items[items.length - 1]!.items!.push(af);
|
||||
listItemIndex++;
|
||||
} else {
|
||||
listItemIndex = 1;
|
||||
items.push({
|
||||
height: fileItemHeight,
|
||||
tag: "file",
|
||||
items: [af],
|
||||
itemStartIndex: index,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSmallerLayout) {
|
||||
rows = mergeTimeStampList(rows, columns);
|
||||
items = mergeTimeStampList(items, columns);
|
||||
}
|
||||
|
||||
if (rows.length == 1) {
|
||||
rows.push({
|
||||
item: (
|
||||
if (items.length == 1) {
|
||||
items.push({
|
||||
height: height - 48,
|
||||
component: (
|
||||
<NoFilesContainer span={columns}>
|
||||
<Typography sx={{ color: "text.faint" }}>
|
||||
{t("nothing_here")}
|
||||
</Typography>
|
||||
</NoFilesContainer>
|
||||
),
|
||||
id: "empty-list-banner",
|
||||
height: height - 48,
|
||||
});
|
||||
}
|
||||
|
||||
const footerHeight = footer?.height ?? 0;
|
||||
rows.push(getVacuumItem(rows, footerHeight));
|
||||
if (footer) {
|
||||
rows.push(asFullSpanListItem(footer));
|
||||
let leftoverHeight = height - (footer?.height ?? 0);
|
||||
for (const item of items) {
|
||||
leftoverHeight -= item.height;
|
||||
if (leftoverHeight <= 0) break;
|
||||
}
|
||||
if (leftoverHeight > 0) {
|
||||
items.push({ height: leftoverHeight, component: <></> });
|
||||
}
|
||||
|
||||
setRows(rows);
|
||||
// Refresh list.
|
||||
listRef.current?.resetAfterIndex(0);
|
||||
// TODO:
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
if (footer) items.push(asFullSpanListItem(footer));
|
||||
|
||||
setItems(items);
|
||||
}, [
|
||||
width,
|
||||
height,
|
||||
@@ -322,181 +361,32 @@ export const FileList: React.FC<FileListProps> = ({
|
||||
layoutParams,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
// Refresh list
|
||||
listRef.current?.resetAfterIndex(0);
|
||||
}, [items]);
|
||||
|
||||
// TODO: Too many non-null assertions
|
||||
|
||||
const groupByTime = (timeStampList: FileListRow[]) => {
|
||||
let listItemIndex = 0;
|
||||
let lastCreationTime: number | undefined;
|
||||
annotatedFiles.forEach((item, index) => {
|
||||
const creationTime = fileCreationTime(item.file) / 1000;
|
||||
if (
|
||||
!lastCreationTime ||
|
||||
!isSameDay(new Date(creationTime), new Date(lastCreationTime))
|
||||
) {
|
||||
lastCreationTime = creationTime;
|
||||
|
||||
timeStampList.push({
|
||||
tag: "date",
|
||||
date: item.timelineDateString,
|
||||
id: lastCreationTime.toString(),
|
||||
});
|
||||
timeStampList.push({
|
||||
tag: "file",
|
||||
items: [item],
|
||||
itemStartIndex: index,
|
||||
});
|
||||
listItemIndex = 1;
|
||||
} else if (listItemIndex < columns) {
|
||||
timeStampList[timeStampList.length - 1]!.items!.push(item);
|
||||
listItemIndex++;
|
||||
} else {
|
||||
listItemIndex = 1;
|
||||
timeStampList.push({
|
||||
tag: "file",
|
||||
items: [item],
|
||||
itemStartIndex: index,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const getVacuumItem = (rows: FileListRow[], footerHeight: number) => {
|
||||
const fileListHeight = (() => {
|
||||
let sum = 0;
|
||||
const getCurrentItemSize = getItemSize(rows);
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
sum += getCurrentItemSize(i);
|
||||
if (height - sum <= footerHeight) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
})();
|
||||
return {
|
||||
item: <></>,
|
||||
height: Math.max(height - fileListHeight - footerHeight, 0),
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks and merge multiple dates into a single row.
|
||||
*/
|
||||
const mergeTimeStampList = (
|
||||
items: FileListRow[],
|
||||
columns: number,
|
||||
): FileListRow[] => {
|
||||
const newList: FileListRow[] = [];
|
||||
let index = 0;
|
||||
let newIndex = 0;
|
||||
while (index < items.length) {
|
||||
const currItem = items[index]!;
|
||||
// If the current item is of type time, then it is not part of an ongoing date.
|
||||
// So, there is a possibility of merge.
|
||||
if (currItem.tag == "date") {
|
||||
// If new list pointer is not at the end of list then
|
||||
// we can add more items to the same list.
|
||||
if (newList[newIndex]) {
|
||||
const SPACE_BTW_DATES_TO_IMAGE_CONTAINER_WIDTH_RATIO = 0.244;
|
||||
// Check if items can be added to same list
|
||||
if (
|
||||
newList[newIndex + 1]!.items!.length +
|
||||
items[index + 1]!.items!.length +
|
||||
Math.ceil(
|
||||
newList[newIndex]!.dates!.length *
|
||||
SPACE_BTW_DATES_TO_IMAGE_CONTAINER_WIDTH_RATIO,
|
||||
) <=
|
||||
columns
|
||||
) {
|
||||
newList[newIndex]!.dates!.push({
|
||||
date: currItem.date!,
|
||||
span: items[index + 1]!.items!.length,
|
||||
});
|
||||
newList[newIndex + 1]!.items = [
|
||||
...newList[newIndex + 1]!.items!,
|
||||
...items[index + 1]!.items!,
|
||||
];
|
||||
index += 2;
|
||||
} else {
|
||||
// Adding items would exceed the number of columns.
|
||||
// So, move new list pointer to the end. Hence, in next iteration,
|
||||
// items will be added to a new list.
|
||||
newIndex += 2;
|
||||
}
|
||||
} else {
|
||||
// New list pointer was at the end of list so simply add new items to the list.
|
||||
newList.push({
|
||||
...currItem,
|
||||
date: null,
|
||||
dates: [
|
||||
{
|
||||
date: currItem.date!,
|
||||
span: items[index + 1]!.items!.length,
|
||||
},
|
||||
],
|
||||
});
|
||||
newList.push(items[index + 1]!);
|
||||
index += 2;
|
||||
}
|
||||
} else {
|
||||
// Merge cannot happen. Simply add all items to new list
|
||||
// and set new list point to the end of list.
|
||||
newList.push(currItem);
|
||||
index++;
|
||||
newIndex = newList.length;
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < newList.length; i++) {
|
||||
const currItem = newList[i]!;
|
||||
const nextItem = newList[i + 1]!;
|
||||
if (currItem.tag == "date") {
|
||||
if (currItem.dates!.length > 1) {
|
||||
currItem.groups = currItem.dates!.map((item) => item.span);
|
||||
nextItem.groups = currItem.groups;
|
||||
}
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
};
|
||||
|
||||
const getItemSize = (timeStampList: FileListRow[]) => (index: number) => {
|
||||
switch (timeStampList[index]!.tag) {
|
||||
case "date":
|
||||
return dateContainerHeight;
|
||||
case "file":
|
||||
return listItemHeight;
|
||||
default:
|
||||
return timeStampList[index]!.height!;
|
||||
}
|
||||
};
|
||||
|
||||
const generateKey = (index: number) => {
|
||||
switch (rows[index]!.tag) {
|
||||
case "file":
|
||||
return `${rows[index]!.items![0]!.file.id}-${
|
||||
rows[index]!.items!.slice(-1)[0]!.file.id
|
||||
}`;
|
||||
default:
|
||||
return `${rows[index]!.id}-${index}`;
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const notSelectedFiles = annotatedFiles.filter(
|
||||
(item) => !selected[item.file.id],
|
||||
(af) => !selected[af.file.id],
|
||||
);
|
||||
|
||||
// Get dates of files which were manually unselected.
|
||||
const unselectedDates = new Set(
|
||||
notSelectedFiles.map((item) => item.timelineDateString),
|
||||
); // to get file's date which were manually unselected
|
||||
|
||||
const localSelectedFiles = annotatedFiles.filter(
|
||||
// to get files which were manually selected
|
||||
(item) => !unselectedDates.has(item.timelineDateString),
|
||||
notSelectedFiles.map((af) => af.timelineDateString),
|
||||
);
|
||||
|
||||
// Get files which were manually selected.
|
||||
const localSelectedFiles = annotatedFiles.filter(
|
||||
(af) => !unselectedDates.has(af.timelineDateString),
|
||||
);
|
||||
|
||||
// Get dates of files which were manually selected.
|
||||
const localSelectedDates = new Set(
|
||||
localSelectedFiles.map((item) => item.timelineDateString),
|
||||
); // to get file's date which were manually selected
|
||||
localSelectedFiles.map((af) => af.timelineDateString),
|
||||
);
|
||||
|
||||
setCheckedTimelineDateStrings((prev) => {
|
||||
const checked = new Set(prev);
|
||||
@@ -508,9 +398,7 @@ export const FileList: React.FC<FileListProps> = ({
|
||||
localSelectedDates.forEach((date) => checked.add(date));
|
||||
return checked;
|
||||
});
|
||||
// TODO:
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selected]);
|
||||
}, [annotatedFiles, selected]);
|
||||
|
||||
const handleSelectMulti = handleSelectCreatorMulti(
|
||||
setSelected,
|
||||
@@ -642,8 +530,9 @@ export const FileList: React.FC<FileListProps> = ({
|
||||
/>
|
||||
);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const renderListItem = (
|
||||
listItem: FileListRow,
|
||||
listItem: FileListItem,
|
||||
isScrolling: boolean | undefined,
|
||||
) => {
|
||||
const haveSelection = selected.count > 0;
|
||||
@@ -716,18 +605,38 @@ export const FileList: React.FC<FileListProps> = ({
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
// TODO:
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return listItem.item;
|
||||
return listItem.component;
|
||||
}
|
||||
};
|
||||
|
||||
if (!rows.length) {
|
||||
const itemData = useMemo(
|
||||
() => ({ items, layoutParams, renderListItem }),
|
||||
[items, layoutParams, renderListItem],
|
||||
);
|
||||
|
||||
const itemSize = useCallback(
|
||||
(index: number) => itemData.items[index]!.height,
|
||||
[itemData],
|
||||
);
|
||||
|
||||
const itemKey = useCallback((index: number, itemData: FileListItemData) => {
|
||||
const item = itemData.items[index]!;
|
||||
switch (item.tag) {
|
||||
case "date":
|
||||
return `${item.date ?? ""}-${index}`;
|
||||
case "file":
|
||||
return `${item.items![0]!.file.id}-${
|
||||
item.items!.slice(-1)[0]!.file.id
|
||||
}`;
|
||||
default:
|
||||
return `${index}`;
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (!items.length) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const itemData = createItemData(rows, layoutParams, renderListItem);
|
||||
|
||||
// The old, mode unaware, behaviour.
|
||||
let key = `${activeCollectionID}`;
|
||||
if (modePlus) {
|
||||
@@ -747,21 +656,97 @@ export const FileList: React.FC<FileListProps> = ({
|
||||
return (
|
||||
<VariableSizeList
|
||||
key={key}
|
||||
itemData={itemData}
|
||||
ref={listRef}
|
||||
itemSize={getItemSize(rows)}
|
||||
height={height}
|
||||
width={width}
|
||||
itemCount={rows.length}
|
||||
itemKey={generateKey}
|
||||
{...{ width, height, itemData, itemSize, itemKey }}
|
||||
itemCount={items.length}
|
||||
overscanCount={3}
|
||||
useIsScrolling
|
||||
>
|
||||
{FileListItem}
|
||||
{FileListRow}
|
||||
</VariableSizeList>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks and merge multiple dates into a single row.
|
||||
*/
|
||||
const mergeTimeStampList = (
|
||||
items: FileListItem[],
|
||||
columns: number,
|
||||
): FileListItem[] => {
|
||||
const newList: FileListItem[] = [];
|
||||
let index = 0;
|
||||
let newIndex = 0;
|
||||
while (index < items.length) {
|
||||
const currItem = items[index]!;
|
||||
// If the current item is of type time, then it is not part of an ongoing date.
|
||||
// So, there is a possibility of merge.
|
||||
if (currItem.tag == "date") {
|
||||
// If new list pointer is not at the end of list then
|
||||
// we can add more items to the same list.
|
||||
if (newList[newIndex]) {
|
||||
const SPACE_BTW_DATES_TO_IMAGE_CONTAINER_WIDTH_RATIO = 0.244;
|
||||
// Check if items can be added to same list
|
||||
if (
|
||||
newList[newIndex + 1]!.items!.length +
|
||||
items[index + 1]!.items!.length +
|
||||
Math.ceil(
|
||||
newList[newIndex]!.dates!.length *
|
||||
SPACE_BTW_DATES_TO_IMAGE_CONTAINER_WIDTH_RATIO,
|
||||
) <=
|
||||
columns
|
||||
) {
|
||||
newList[newIndex]!.dates!.push({
|
||||
date: currItem.date!,
|
||||
span: items[index + 1]!.items!.length,
|
||||
});
|
||||
newList[newIndex + 1]!.items = [
|
||||
...newList[newIndex + 1]!.items!,
|
||||
...items[index + 1]!.items!,
|
||||
];
|
||||
index += 2;
|
||||
} else {
|
||||
// Adding items would exceed the number of columns.
|
||||
// So, move new list pointer to the end. Hence, in next iteration,
|
||||
// items will be added to a new list.
|
||||
newIndex += 2;
|
||||
}
|
||||
} else {
|
||||
// New list pointer was at the end of list so simply add new items to the list.
|
||||
newList.push({
|
||||
...currItem,
|
||||
date: null,
|
||||
dates: [
|
||||
{
|
||||
date: currItem.date!,
|
||||
span: items[index + 1]!.items!.length,
|
||||
},
|
||||
],
|
||||
});
|
||||
newList.push(items[index + 1]!);
|
||||
index += 2;
|
||||
}
|
||||
} else {
|
||||
// Merge cannot happen. Simply add all items to new list
|
||||
// and set new list point to the end of list.
|
||||
newList.push(currItem);
|
||||
index++;
|
||||
newIndex = newList.length;
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < newList.length; i++) {
|
||||
const currItem = newList[i]!;
|
||||
const nextItem = newList[i + 1]!;
|
||||
if (currItem.tag == "date") {
|
||||
if (currItem.dates!.length > 1) {
|
||||
currItem.groups = currItem.dates!.map((item) => item.span);
|
||||
nextItem.groups = currItem.groups;
|
||||
}
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
};
|
||||
|
||||
const ListItem = styled("div")`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -807,12 +792,14 @@ const FullSpanListItemContainer = styled("div")`
|
||||
`;
|
||||
|
||||
/**
|
||||
* Convert a {@link FileListHeaderOrFooter} into a {@link FileListRow}
|
||||
* Convert a {@link FileListHeaderOrFooter} into a {@link FileListItem}
|
||||
* that spans all columns.
|
||||
*/
|
||||
const asFullSpanListItem = ({ item, ...rest }: FileListHeaderOrFooter) => ({
|
||||
...rest,
|
||||
item: <FullSpanListItemContainer>{item}</FullSpanListItemContainer>,
|
||||
const asFullSpanListItem = ({ component, height }: FileListHeaderOrFooter) => ({
|
||||
height,
|
||||
component: (
|
||||
<FullSpanListItemContainer>{component}</FullSpanListItemContainer>
|
||||
),
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -836,26 +823,15 @@ const NoFilesContainer = styled(ListItemContainer)`
|
||||
`;
|
||||
|
||||
interface FileListItemData {
|
||||
items: FileListRow[];
|
||||
items: FileListItem[];
|
||||
layoutParams: ThumbnailGridLayoutParams;
|
||||
renderListItem: (
|
||||
timeStampListItem: FileListRow,
|
||||
timeStampListItem: FileListItem,
|
||||
isScrolling?: boolean,
|
||||
) => React.JSX.Element;
|
||||
}
|
||||
|
||||
const createItemData = memoize(
|
||||
(
|
||||
rowDatas: FileListRow[],
|
||||
layoutParams: ThumbnailGridLayoutParams,
|
||||
renderListItem: (
|
||||
timeStampListItem: FileListRow,
|
||||
isScrolling?: boolean,
|
||||
) => React.JSX.Element,
|
||||
): FileListItemData => ({ items: rowDatas, layoutParams, renderListItem }),
|
||||
);
|
||||
|
||||
const FileListItem = memo(
|
||||
const FileListRow = memo(
|
||||
({
|
||||
index,
|
||||
style,
|
||||
|
||||
@@ -412,7 +412,7 @@ const Page: React.FC = () => {
|
||||
useEffect(() => {
|
||||
if (isInSearchMode && state.searchSuggestion) {
|
||||
setFileListHeader({
|
||||
item: (
|
||||
component: (
|
||||
<SearchResultsHeader
|
||||
searchSuggestion={state.searchSuggestion}
|
||||
fileCount={state.searchResults?.length ?? 0}
|
||||
@@ -1396,7 +1396,7 @@ const handleSubscriptionCompletionRedirectIfNeeded = async (
|
||||
};
|
||||
|
||||
const createAppDownloadFooter = (): FileListHeaderOrFooter => ({
|
||||
item: (
|
||||
component: (
|
||||
<Typography
|
||||
variant="small"
|
||||
sx={{
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
} from "@mui/material";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { DownloadStatusNotifications } from "components/DownloadStatusNotifications";
|
||||
import { type FileListHeaderOrFooter } from "components/FileList";
|
||||
import { FileListWithViewer } from "components/FileListWithViewer";
|
||||
import { Upload } from "components/Upload";
|
||||
import {
|
||||
@@ -393,11 +394,11 @@ export default function PublicCollectionGallery() {
|
||||
setUploadTypeSelectorView(false);
|
||||
};
|
||||
|
||||
const fileListHeader = useMemo(
|
||||
const fileListHeader = useMemo<FileListHeaderOrFooter | undefined>(
|
||||
() =>
|
||||
publicCollection && publicFiles
|
||||
? {
|
||||
item: (
|
||||
component: (
|
||||
<FileListHeader
|
||||
{...{
|
||||
publicCollection,
|
||||
@@ -413,10 +414,10 @@ export default function PublicCollectionGallery() {
|
||||
[onAddSaveGroup, publicCollection, publicFiles, downloadEnabled],
|
||||
);
|
||||
|
||||
const fileListFooter = useMemo(() => {
|
||||
const fileListFooter = useMemo<FileListHeaderOrFooter>(() => {
|
||||
const props = { referralCode, onAddPhotos };
|
||||
return {
|
||||
item: <FileListFooter {...props} />,
|
||||
component: <FileListFooter {...props} />,
|
||||
height: fileListFooterHeightForProps(props),
|
||||
};
|
||||
}, [referralCode, onAddPhotos]);
|
||||
|
||||
Reference in New Issue
Block a user