Files
userbase/app/src/ui/elements/media/DropzoneContainer.tsx
T

115 lines
3.4 KiB
TypeScript

import type { Api } from "bknd/client";
import type { RepoQueryIn } from "data";
import type { MediaFieldSchema } from "media/AppMedia";
import type { TAppMediaConfig } from "media/media-schema";
import { type ReactNode, createContext, useContext, useId } from "react";
import { useApi, useApiQuery, useInvalidate } from "ui/client";
import { useEvent } from "ui/hooks/use-event";
import { Dropzone, type DropzoneProps, type DropzoneRenderProps, type FileState } from "./Dropzone";
import { mediaItemsToFileStates } from "./helper";
export type DropzoneContainerProps = {
children?: ReactNode;
initialItems?: MediaFieldSchema[] | false;
entity?: {
name: string;
id: number;
field: string;
};
media?: Pick<TAppMediaConfig, "entity_name" | "storage">;
query?: RepoQueryIn;
randomFilename?: boolean;
} & Omit<Partial<DropzoneProps>, "children" | "initialItems">;
const DropzoneContainerContext = createContext<DropzoneRenderProps>(undefined!);
export function DropzoneContainer({
initialItems,
media,
entity,
query,
children,
randomFilename,
...props
}: DropzoneContainerProps) {
const id = useId();
const api = useApi();
const invalidate = useInvalidate();
const baseUrl = api.baseUrl;
const defaultQuery = {
limit: query?.limit ? query?.limit : props.maxItems ? props.maxItems : 50,
sort: "-id"
};
const entity_name = (media?.entity_name ?? "media") as "media";
//console.log("dropzone:baseUrl", baseUrl);
const selectApi = (api: Api) =>
entity
? api.data.readManyByReference(entity.name, entity.id, entity.field, {
...defaultQuery,
...query,
where: {
reference: `${entity.name}.${entity.field}`,
entity_id: entity.id,
...query?.where
}
})
: api.data.readMany(entity_name, {
...defaultQuery,
...query
});
const $q = useApiQuery(selectApi, { enabled: initialItems !== false && !initialItems });
const getUploadInfo = useEvent((file) => {
const url = entity
? api.media.getEntityUploadUrl(entity.name, entity.id, entity.field)
: api.media.getFileUploadUrl(randomFilename ? undefined : file);
return {
url,
headers: api.media.getUploadHeaders(),
method: "POST"
};
});
const refresh = useEvent(async () => {
await invalidate($q.promise.key({ search: false }));
});
const handleDelete = useEvent(async (file: FileState) => {
return api.media.deleteFile(file.path);
});
const actualItems = (initialItems ??
(Array.isArray($q.data) ? $q.data : []) ??
[]) as MediaFieldSchema[];
const _initialItems = mediaItemsToFileStates(actualItems, { baseUrl });
const key = id + JSON.stringify(_initialItems);
return (
<Dropzone
key={id + key}
getUploadInfo={getUploadInfo}
handleDelete={handleDelete}
onUploaded={refresh}
onDeleted={refresh}
autoUpload
initialItems={_initialItems}
{...props}
>
{children
? (props) => (
<DropzoneContainerContext.Provider value={props}>
{children}
</DropzoneContainerContext.Provider>
)
: undefined}
</Dropzone>
);
}
export function useDropzone() {
return useContext(DropzoneContainerContext);
}