Haystack/frontend/src/contexts/SearchImageContext.tsx

100 lines
3.1 KiB
TypeScript

import {
type Accessor,
type Component,
type ParentProps,
createContext,
createMemo,
createResource,
useContext,
} from "solid-js";
import { deleteImage, deleteImageFromStack, getUserImages, JustTheImageWhatAreTheseNames, reprocessImage } from "../network";
export type SearchImageStore = {
imagesByDate: Accessor<
Array<{ date: Date; images: JustTheImageWhatAreTheseNames }>
>;
lists: Accessor<Awaited<ReturnType<typeof getUserImages>>["lists"]>;
userImages: Accessor<JustTheImageWhatAreTheseNames>;
processingImages: Accessor<
Awaited<ReturnType<typeof getUserImages>>["processingImages"] | undefined
>;
onRefetchImages: () => void;
onDeleteImage: (imageID: string) => void;
onDeleteImageFromStack: (stackID: string, imageID: string) => void;
onRefreshImage: (imageID: string) => void;
};
const SearchImageContext = createContext<SearchImageStore>();
export const SearchImageContextProvider: Component<ParentProps> = (props) => {
const [data, { refetch }] = createResource(getUserImages);
const sortedImages = createMemo<ReturnType<SearchImageStore["imagesByDate"]>>(
() => {
const d = data();
if (d == null) {
return [];
}
// Sorted by day. But we could potentially add more in the future.
const buckets: Record<string, JustTheImageWhatAreTheseNames> = {};
for (const image of d.userImages) {
if (image.CreatedAt == null) {
continue;
}
const date = new Date(image.CreatedAt).toDateString();
if (!(date in buckets)) {
buckets[date] = [];
}
buckets[date].push(image);
}
return Object.entries(buckets)
.map(([date, images]) => ({ date: new Date(date), images }))
.sort((a, b) => b.date.getTime() - a.date.getTime());
},
);
const processingImages = () => data()?.processingImages ?? [];
return (
<SearchImageContext.Provider
value={{
imagesByDate: sortedImages,
lists: () => data()?.lists ?? [],
userImages: () => data()?.userImages ?? [],
processingImages,
onRefetchImages: refetch,
onDeleteImage: (imageID: string) => {
deleteImage(imageID).then(refetch);
},
onDeleteImageFromStack: (stackID: string, imageID: string) => {
deleteImageFromStack(stackID, imageID).then(refetch);
},
onRefreshImage: (imageID: string) => {
reprocessImage(imageID).then(refetch)
}
}}
>
{props.children}
</SearchImageContext.Provider>
);
};
export const useSearchImageContext = () => {
const context = useContext(SearchImageContext);
if (context == null) {
throw new Error(
"Unreachable: We should always have a mounted context and no undefined values",
);
}
return context;
};