Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions packages/react/src/components/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
import type { CSSProperties } from "react";
import { useCallback, useMemo, useRef, useState } from "react";

import type {
ContentField,
ErrorMessage,
StyleField,
} from "@uploadthing/shared";
import {
allowedContentTextLabelGenerator,
contentFieldToContent,
Expand All @@ -15,11 +20,6 @@ import {
styleFieldToCssObject,
UploadAbortedError,
} from "@uploadthing/shared";
import type {
ContentField,
ErrorMessage,
StyleField,
} from "@uploadthing/shared";
import type { FileRouter } from "uploadthing/types";

import type { UploadthingComponentProps } from "../types";
Expand Down Expand Up @@ -116,6 +116,7 @@ export function UploadButton<
{
signal: acRef.current.signal,
headers: $props.headers,
onFileUploadComplete: $props.onFileUploadComplete,
onClientUploadComplete: (res) => {
if (fileInputRef.current) {
fileInputRef.current.value = "";
Expand Down
19 changes: 19 additions & 0 deletions packages/react/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,25 @@ export type UseUploadthingProps<
TFileRoute extends AnyFileRoute,
TServerOutput = inferEndpointOutput<TFileRoute>,
> = {
/**
* Called when a file upload is completed
*/
onFileUploadComplete?:
| ((_: {
/**
* The response from the upload
*/
fileData: ClientUploadedFileData<TServerOutput>;
/**
* The file object that was uploaded
*/
file: File;
/**
* All the files that are in this upload
*/
files: File[];
}) => void)
| undefined;
/**
* Called when the upload is submitted and the server is about to be queried for presigned URLs
* Can be used to modify the files before they are uploaded, e.g. renaming them
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/use-uploadthing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ function useUploadThingInternal<
signal: opts?.signal,
headers: opts?.headers,
files,
onFileUploadComplete: opts?.onFileUploadComplete,
onUploadProgress: (progress) => {
if (!opts?.onUploadProgress) return;
fileProgress.current.set(progress.file, progress.progress);
Expand Down
14 changes: 10 additions & 4 deletions packages/uploadthing/src/_internal/upload-browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,8 @@ export const uploadFile = <
file: File,
presigned: NewPresignedUrl,
opts: {
onUploadProgress?: (progressEvent: {
loaded: number;
delta: number;
}) => void;
onFileUploadComplete?: (_: ClientUploadedFileData<TServerOutput>) => void;
onUploadProgress?: (_: { loaded: number; delta: number }) => void;
},
) =>
fetchEff(presigned.url, { method: "HEAD" }).pipe(
Expand Down Expand Up @@ -156,6 +154,7 @@ export const uploadFile = <
type: file.type,
fileHash: uploadResponse.fileHash,
})),
Micro.tap((fileData) => opts.onFileUploadComplete?.(fileData)),
);

export const uploadFilesInternal = <
Expand Down Expand Up @@ -204,6 +203,13 @@ export const uploadFilesInternal = <
opts.files[i]!,
presigned,
{
onFileUploadComplete: (result) => {
opts.onFileUploadComplete?.({
fileData: result,
file: opts.files[i]!,
files: opts.files,
});
},
onUploadProgress: (ev) => {
totalLoaded += ev.delta;
opts.onUploadProgress?.({
Expand Down
20 changes: 20 additions & 0 deletions packages/uploadthing/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {

import type { LogFormat } from "./_internal/logger";
import type { AnyFileRoute, FileRoute } from "./_internal/types";
import type { ClientUploadedFileData } from "./types";

export * from "./sdk/types";

Expand Down Expand Up @@ -124,6 +125,25 @@ export type UploadFilesOptions<TFileRoute extends AnyFileRoute> = {
totalProgress: number;
}) => void)
| undefined;
/**
* Called when a file upload is completed
*/
onFileUploadComplete?:
| ((_: {
/**
* The response from the upload
*/
fileData: ClientUploadedFileData<inferEndpointOutput<TFileRoute>>;
/**
* The file object that was uploaded
*/
file: File;
/**
* All the files that are in this upload
*/
files: File[];
}) => void)
| undefined;
/**
* This option has been moved to your serverside route config.
* Please opt-in by setting `awaitServerData: false` in your route
Expand Down