# file

## Client

- Query:
  `fileMetasQueryOptions`
  `fileThumbnailQueryOptions`
  `fileQueryOptions`
- Mutation:
  `downloadFileMutationOptions`
  `openFileMutationOptions`
  `updateFileMetaMutationOptions`
  `deleteFileMutationOptions`
  `batchDeleteFilesMutationOptions`
  `uploadFileMutationOptions`

## Server

- Fetch:
  `getFileMetas`
  `getFileThumbnail`
  `getFile`
  `downloadFile`
- Mutate:
  `updateFileMeta`
  `deleteFile`
  `batchDeleteFiles`
  `uploadFile`

## Schemas/Models

```ts
const FileMetaSchema = z.object({
  id: z.uuid(),
  subId: z.uuid(),
  appName: z.string().trim().min(1).max(255),
  fileName: z.string().trim().min(1).max(255),
  fileExtension: z.string().trim().min(1).max(255),
  fileSize: z.number().min(0),
  mediaSubType: z.string().trim().min(1).max(255),
  mediaType: z.string().trim().min(1).max(255),
  mimeType: z.string().trim().min(1).max(255),
  createdBy: z.string().trim().min(1).max(255),
  createdDate: z.date(),
});

const GetFileMetasSchema = z.object({
  appName: z.string().min(1).max(255),
  subId: z.uuid(),
});

const FileSchema = z.object({
  appName: z.string().min(1).max(255),
  id: z.uuid(),
});

const UpdateFileMetaSchema = FileMetaSchema.extend({
  fileName: z.string().min(1).max(255),
});

const UploadFileMetaSchema = z.object({
  appName: z.string().min(1).max(255),
  subId: z.uuid(),
  file: z.instanceof(File),
});
```

## Examples

```ts
import { fileMetasQueryOptions, fileQueryOptions, uploadFileMutationOptions } from "wcz-layout/data/client";
import { Dropzone, FileViewer } from "wcz-layout/components";
import { useInView } from "wcz-layout/hooks";

// fetch metas + fetch first file
const { ref, inView } = useInView();

const { data: fileMetas = [] } = useQuery({
  ...fileMetasQueryOptions({ appName: packageJson.name, subId }),
  enabled: inView,
});

const { data: file } = useQuery({
  ...fileQueryOptions({ appName: packageJson.name, id: fileMetas[0]?.id ?? "" }),
  enabled: !!fileMetas[0],
});

// upload
const [progress, setProgress] = useState(0);
const { mutateAsync: uploadFile } = useMutation(uploadFileMutationOptions({ queryClient }));

// Dropzone
const onDrop = async (acceptedFiles: File[]) => {
  await Promise.allSettled(
    acceptedFiles.map((file) =>
      uploadFile({ appName: packageJson.name, subId, file, setProgress }),
    ),
  );
  setUploadProgress(0);
};

<Dropzone onDrop={onDrop} progress={progress} />

// File Viewer - no manual fetch metas needed (default)
<FileViewer appName={packageJson.name} subId={subId}>
  {(component) => <component.Grid />} // or component.List
</FileViewer>
```
